viem 2.51.3 → 2.52.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/_cjs/errors/version.js +1 -1
  3. package/_cjs/tempo/Abis.js +189 -1
  4. package/_cjs/tempo/Abis.js.map +1 -1
  5. package/_cjs/tempo/Account.js +27 -20
  6. package/_cjs/tempo/Account.js.map +1 -1
  7. package/_cjs/tempo/Addresses.js +3 -1
  8. package/_cjs/tempo/Addresses.js.map +1 -1
  9. package/_cjs/tempo/Decorator.js +23 -0
  10. package/_cjs/tempo/Decorator.js.map +1 -1
  11. package/_cjs/tempo/Hardfork.js +3 -0
  12. package/_cjs/tempo/Hardfork.js.map +1 -1
  13. package/_cjs/tempo/actions/accessKey.js +238 -72
  14. package/_cjs/tempo/actions/accessKey.js.map +1 -1
  15. package/_cjs/tempo/actions/index.js +2 -1
  16. package/_cjs/tempo/actions/index.js.map +1 -1
  17. package/_cjs/tempo/actions/receivePolicy.js +363 -0
  18. package/_cjs/tempo/actions/receivePolicy.js.map +1 -0
  19. package/_cjs/tempo/index.js +2 -1
  20. package/_cjs/tempo/index.js.map +1 -1
  21. package/_esm/errors/version.js +1 -1
  22. package/_esm/tempo/Abis.js +188 -0
  23. package/_esm/tempo/Abis.js.map +1 -1
  24. package/_esm/tempo/Account.js +35 -20
  25. package/_esm/tempo/Account.js.map +1 -1
  26. package/_esm/tempo/Addresses.js +2 -0
  27. package/_esm/tempo/Addresses.js.map +1 -1
  28. package/_esm/tempo/Decorator.js +23 -0
  29. package/_esm/tempo/Decorator.js.map +1 -1
  30. package/_esm/tempo/Hardfork.js +3 -0
  31. package/_esm/tempo/Hardfork.js.map +1 -1
  32. package/_esm/tempo/actions/accessKey.js +562 -128
  33. package/_esm/tempo/actions/accessKey.js.map +1 -1
  34. package/_esm/tempo/actions/index.js +1 -0
  35. package/_esm/tempo/actions/index.js.map +1 -1
  36. package/_esm/tempo/actions/receivePolicy.js +753 -0
  37. package/_esm/tempo/actions/receivePolicy.js.map +1 -0
  38. package/_esm/tempo/index.js +1 -1
  39. package/_esm/tempo/index.js.map +1 -1
  40. package/_types/errors/version.d.ts +1 -1
  41. package/_types/tempo/Abis.d.ts +671 -4
  42. package/_types/tempo/Abis.d.ts.map +1 -1
  43. package/_types/tempo/Account.d.ts +13 -2
  44. package/_types/tempo/Account.d.ts.map +1 -1
  45. package/_types/tempo/Addresses.d.ts +2 -0
  46. package/_types/tempo/Addresses.d.ts.map +1 -1
  47. package/_types/tempo/Decorator.d.ts +501 -0
  48. package/_types/tempo/Decorator.d.ts.map +1 -1
  49. package/_types/tempo/Hardfork.d.ts +1 -1
  50. package/_types/tempo/Hardfork.d.ts.map +1 -1
  51. package/_types/tempo/actions/accessKey.d.ts +1520 -304
  52. package/_types/tempo/actions/accessKey.d.ts.map +1 -1
  53. package/_types/tempo/actions/dex.d.ts +75 -0
  54. package/_types/tempo/actions/dex.d.ts.map +1 -1
  55. package/_types/tempo/actions/index.d.ts +1 -0
  56. package/_types/tempo/actions/index.d.ts.map +1 -1
  57. package/_types/tempo/actions/policy.d.ts +352 -0
  58. package/_types/tempo/actions/policy.d.ts.map +1 -1
  59. package/_types/tempo/actions/receivePolicy.d.ts +1511 -0
  60. package/_types/tempo/actions/receivePolicy.d.ts.map +1 -0
  61. package/_types/tempo/index.d.ts +1 -1
  62. package/_types/tempo/index.d.ts.map +1 -1
  63. package/errors/version.ts +1 -1
  64. package/package.json +2 -2
  65. package/tempo/Abis.ts +189 -0
  66. package/tempo/Account.ts +56 -27
  67. package/tempo/Addresses.ts +2 -0
  68. package/tempo/Decorator.ts +578 -0
  69. package/tempo/Hardfork.ts +3 -0
  70. package/tempo/actions/accessKey.ts +1002 -279
  71. package/tempo/actions/index.ts +1 -0
  72. package/tempo/actions/receivePolicy.ts +1266 -0
  73. package/tempo/index.ts +1 -0
@@ -1,5 +1,6 @@
1
1
  import { parseAccount } from '../../accounts/utils/parseAccount.js';
2
2
  import { readContract } from '../../actions/public/readContract.js';
3
+ import { watchContractEvent } from '../../actions/public/watchContractEvent.js';
3
4
  import { sendTransaction } from '../../actions/wallet/sendTransaction.js';
4
5
  import { sendTransactionSync } from '../../actions/wallet/sendTransactionSync.js';
5
6
  import { writeContract } from '../../actions/wallet/writeContract.js';
@@ -58,7 +59,7 @@ export async function authorize(client, parameters) {
58
59
  (function (authorize) {
59
60
  /** @internal */
60
61
  async function inner(action, client, parameters) {
61
- const { accessKey, chainId = client.chain?.id, expiry, limits, scopes, ...rest } = parameters;
62
+ const { accessKey, admin, chainId = client.chain?.id, expiry, limits, scopes, witness, ...rest } = parameters;
62
63
  const account_ = rest.account ?? client.account;
63
64
  if (!account_)
64
65
  throw new Error('account is required.');
@@ -68,9 +69,11 @@ export async function authorize(client, parameters) {
68
69
  const keyAuthorization = await signKeyAuthorization(parsed, {
69
70
  chainId: BigInt(chainId),
70
71
  key: accessKey,
72
+ admin,
71
73
  expiry,
72
74
  limits,
73
75
  scopes,
76
+ witness,
74
77
  });
75
78
  return (await action(client, {
76
79
  ...rest,
@@ -134,6 +137,398 @@ export async function authorizeSync(client, parameters) {
134
137
  receipt,
135
138
  };
136
139
  }
140
+ /**
141
+ * Burns a key-authorization witness, invalidating any authorization bound to
142
+ * it before it is submitted onchain.
143
+ *
144
+ * Once burned, an `authorizeKey` call carrying the same `witness` will revert.
145
+ * This lets applications issue a signed authorization offchain (see
146
+ * {@link authorize}) while retaining the ability to revoke it.
147
+ *
148
+ * [TIP-1053](https://tips.sh/1053)
149
+ *
150
+ * @example
151
+ * ```ts
152
+ * import { createClient, http } from 'viem'
153
+ * import { tempo } from 'viem/chains'
154
+ * import { Actions } from 'viem/tempo'
155
+ * import { privateKeyToAccount } from 'viem/accounts'
156
+ *
157
+ * const client = createClient({
158
+ * account: privateKeyToAccount('0x...'),
159
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
160
+ * transport: http(),
161
+ * })
162
+ *
163
+ * const hash = await Actions.accessKey.burnWitness(client, {
164
+ * witness: '0x...',
165
+ * })
166
+ * ```
167
+ *
168
+ * @param client - Client.
169
+ * @param parameters - Parameters.
170
+ * @returns The transaction hash.
171
+ */
172
+ export async function burnWitness(client, parameters) {
173
+ return burnWitness.inner(writeContract, client, parameters);
174
+ }
175
+ (function (burnWitness) {
176
+ /** @internal */
177
+ async function inner(action, client, parameters) {
178
+ const { witness, ...rest } = parameters;
179
+ const call = burnWitness.call({ witness });
180
+ return (await action(client, {
181
+ ...rest,
182
+ ...call,
183
+ }));
184
+ }
185
+ burnWitness.inner = inner;
186
+ /**
187
+ * Defines a call to the `burnKeyAuthorizationWitness` function.
188
+ *
189
+ * Can be passed as a parameter to:
190
+ * - [`estimateContractGas`](https://viem.sh/docs/contract/estimateContractGas): estimate the gas cost of the call
191
+ * - [`simulateContract`](https://viem.sh/docs/contract/simulateContract): simulate the call
192
+ * - [`sendCalls`](https://viem.sh/docs/actions/wallet/sendCalls): send multiple calls
193
+ *
194
+ * @example
195
+ * ```ts
196
+ * import { createClient, http, walletActions } from 'viem'
197
+ * import { tempo } from 'viem/chains'
198
+ * import { Actions } from 'viem/tempo'
199
+ *
200
+ * const client = createClient({
201
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
202
+ * transport: http(),
203
+ * }).extend(walletActions)
204
+ *
205
+ * const hash = await client.sendTransaction({
206
+ * calls: [
207
+ * Actions.accessKey.burnWitness.call({ witness: '0x...' }),
208
+ * ],
209
+ * })
210
+ * ```
211
+ *
212
+ * @param args - Arguments.
213
+ * @returns The call.
214
+ */
215
+ function call(args) {
216
+ const { witness } = args;
217
+ return defineCall({
218
+ address: Addresses.accountKeychain,
219
+ abi: Abis.accountKeychain,
220
+ functionName: 'burnKeyAuthorizationWitness',
221
+ args: [witness],
222
+ });
223
+ }
224
+ burnWitness.call = call;
225
+ function extractEvent(logs) {
226
+ const [log] = parseEventLogs({
227
+ abi: Abis.accountKeychain,
228
+ logs,
229
+ eventName: 'KeyAuthorizationWitnessBurned',
230
+ strict: true,
231
+ });
232
+ if (!log)
233
+ throw new Error('`KeyAuthorizationWitnessBurned` event not found.');
234
+ return log;
235
+ }
236
+ burnWitness.extractEvent = extractEvent;
237
+ })(burnWitness || (burnWitness = {}));
238
+ /**
239
+ * Burns a key-authorization witness and waits for the transaction receipt.
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * import { createClient, http } from 'viem'
244
+ * import { tempo } from 'viem/chains'
245
+ * import { Actions } from 'viem/tempo'
246
+ * import { privateKeyToAccount } from 'viem/accounts'
247
+ *
248
+ * const client = createClient({
249
+ * account: privateKeyToAccount('0x...'),
250
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
251
+ * transport: http(),
252
+ * })
253
+ *
254
+ * const { receipt, ...result } = await Actions.accessKey.burnWitnessSync(client, {
255
+ * witness: '0x...',
256
+ * })
257
+ * ```
258
+ *
259
+ * @param client - Client.
260
+ * @param parameters - Parameters.
261
+ * @returns The transaction receipt and event data.
262
+ */
263
+ export async function burnWitnessSync(client, parameters) {
264
+ const { throwOnReceiptRevert = true, ...rest } = parameters;
265
+ const receipt = await burnWitness.inner(writeContractSync, client, {
266
+ ...rest,
267
+ throwOnReceiptRevert,
268
+ });
269
+ const { args } = burnWitness.extractEvent(receipt.logs);
270
+ return {
271
+ ...args,
272
+ receipt,
273
+ };
274
+ }
275
+ /**
276
+ * Gets access key information.
277
+ *
278
+ * @example
279
+ * ```ts
280
+ * import { createClient, http } from 'viem'
281
+ * import { tempo } from 'viem/chains'
282
+ * import { Actions } from 'viem/tempo'
283
+ *
284
+ * const client = createClient({
285
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
286
+ * transport: http(),
287
+ * })
288
+ *
289
+ * const key = await Actions.accessKey.getMetadata(client, {
290
+ * account: '0x...',
291
+ * accessKey: '0x...',
292
+ * })
293
+ * ```
294
+ *
295
+ * @param client - Client.
296
+ * @param parameters - Parameters.
297
+ * @returns The key information.
298
+ */
299
+ export async function getMetadata(client, parameters) {
300
+ const { account: account_ = client.account, accessKey, ...rest } = parameters;
301
+ if (!account_)
302
+ throw new Error('account is required.');
303
+ const account = parseAccount(account_);
304
+ const result = await readContract(client, {
305
+ ...rest,
306
+ account: null,
307
+ ...getMetadata.call({ account: account.address, accessKey }),
308
+ });
309
+ return {
310
+ address: result.keyId,
311
+ keyType: signatureTypes[result.signatureType] ??
312
+ 'secp256k1',
313
+ expiry: result.expiry,
314
+ spendPolicy: spendPolicies[`${result.enforceLimits}`],
315
+ isRevoked: result.isRevoked,
316
+ };
317
+ }
318
+ (function (getMetadata) {
319
+ /**
320
+ * Defines a call to the `getKey` function.
321
+ *
322
+ * @param args - Arguments.
323
+ * @returns The call.
324
+ */
325
+ function call(args) {
326
+ const { account, accessKey } = args;
327
+ return defineCall({
328
+ address: Addresses.accountKeychain,
329
+ abi: Abis.accountKeychain,
330
+ functionName: 'getKey',
331
+ args: [account, resolveAccessKeyAddress(accessKey)],
332
+ });
333
+ }
334
+ getMetadata.call = call;
335
+ })(getMetadata || (getMetadata = {}));
336
+ /**
337
+ * Gets the remaining spending limit for a key-token pair.
338
+ *
339
+ * @example
340
+ * ```ts
341
+ * import { createClient, http } from 'viem'
342
+ * import { tempo } from 'viem/chains'
343
+ * import { Actions } from 'viem/tempo'
344
+ *
345
+ * const client = createClient({
346
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
347
+ * transport: http(),
348
+ * })
349
+ *
350
+ * const { remaining, periodEnd } = await Actions.accessKey.getRemainingLimit(client, {
351
+ * account: '0x...',
352
+ * accessKey: '0x...',
353
+ * token: '0x...',
354
+ * })
355
+ *
356
+ * console.log(remaining, periodEnd)
357
+ * ```
358
+ *
359
+ * @param client - Client.
360
+ * @param parameters - Parameters.
361
+ * @returns The remaining spending amount and period end timestamp.
362
+ */
363
+ export async function getRemainingLimit(client, parameters) {
364
+ const { account: account_ = client.account, accessKey, token, ...rest } = parameters;
365
+ if (!account_)
366
+ throw new Error('account is required.');
367
+ const account = parseAccount(account_);
368
+ // TODO: remove pre-t3 branch once mainnet is on t3.
369
+ const hardfork = client.chain?.hardfork;
370
+ if (hardfork && Hardfork.lt(hardfork, 't3')) {
371
+ const remaining = await readContract(client, {
372
+ ...rest,
373
+ ...getRemainingLimit.call({ account: account.address, accessKey, token }),
374
+ });
375
+ return { remaining, periodEnd: undefined };
376
+ }
377
+ const [remaining, periodEnd] = await readContract(client, {
378
+ ...rest,
379
+ ...getRemainingLimit.callWithPeriod({
380
+ account: account.address,
381
+ accessKey,
382
+ token,
383
+ }),
384
+ });
385
+ return { remaining, periodEnd };
386
+ }
387
+ (function (getRemainingLimit) {
388
+ /**
389
+ * Defines a call to the `getRemainingLimit` function (pre-T3).
390
+ *
391
+ * @param args - Arguments.
392
+ * @returns The call.
393
+ */
394
+ function call(args) {
395
+ const { account, accessKey, token } = args;
396
+ return defineCall({
397
+ address: Addresses.accountKeychain,
398
+ abi: Abis.accountKeychain,
399
+ functionName: 'getRemainingLimit',
400
+ args: [account, resolveAccessKeyAddress(accessKey), token],
401
+ });
402
+ }
403
+ getRemainingLimit.call = call;
404
+ /**
405
+ * Defines a call to the `getRemainingLimitWithPeriod` function (T3+).
406
+ *
407
+ * @param args - Arguments.
408
+ * @returns The call.
409
+ */
410
+ function callWithPeriod(args) {
411
+ const { account, accessKey, token } = args;
412
+ return defineCall({
413
+ address: Addresses.accountKeychain,
414
+ abi: Abis.accountKeychain,
415
+ functionName: 'getRemainingLimitWithPeriod',
416
+ args: [account, resolveAccessKeyAddress(accessKey), token],
417
+ });
418
+ }
419
+ getRemainingLimit.callWithPeriod = callWithPeriod;
420
+ })(getRemainingLimit || (getRemainingLimit = {}));
421
+ /**
422
+ * Checks whether an access key is an admin key for an account.
423
+ *
424
+ * Returns `true` for the account's root key or for an active admin access key
425
+ * (see {@link authorize} with `admin: true`).
426
+ *
427
+ * [TIP-1049](https://tips.sh/1049)
428
+ *
429
+ * @example
430
+ * ```ts
431
+ * import { createClient, http } from 'viem'
432
+ * import { tempo } from 'viem/chains'
433
+ * import { Actions } from 'viem/tempo'
434
+ *
435
+ * const client = createClient({
436
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
437
+ * transport: http(),
438
+ * })
439
+ *
440
+ * const isAdmin = await Actions.accessKey.isAdmin(client, {
441
+ * account: '0x...',
442
+ * accessKey: '0x...',
443
+ * })
444
+ * ```
445
+ *
446
+ * @param client - Client.
447
+ * @param parameters - Parameters.
448
+ * @returns Whether the access key is an admin key.
449
+ */
450
+ export async function isAdmin(client, parameters) {
451
+ const { account: account_ = client.account, accessKey, ...rest } = parameters;
452
+ if (!account_)
453
+ throw new Error('account is required.');
454
+ const account = parseAccount(account_);
455
+ return readContract(client, {
456
+ ...rest,
457
+ account: null,
458
+ ...isAdmin.call({ account: account.address, accessKey }),
459
+ });
460
+ }
461
+ (function (isAdmin) {
462
+ /**
463
+ * Defines a call to the `isAdminKey` function.
464
+ *
465
+ * @param args - Arguments.
466
+ * @returns The call.
467
+ */
468
+ function call(args) {
469
+ const { account, accessKey } = args;
470
+ return defineCall({
471
+ address: Addresses.accountKeychain,
472
+ abi: Abis.accountKeychain,
473
+ functionName: 'isAdminKey',
474
+ args: [account, resolveAccessKeyAddress(accessKey)],
475
+ });
476
+ }
477
+ isAdmin.call = call;
478
+ })(isAdmin || (isAdmin = {}));
479
+ /**
480
+ * Checks whether a key-authorization witness has been burned for an account.
481
+ *
482
+ * @example
483
+ * ```ts
484
+ * import { createClient, http } from 'viem'
485
+ * import { tempo } from 'viem/chains'
486
+ * import { Actions } from 'viem/tempo'
487
+ *
488
+ * const client = createClient({
489
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
490
+ * transport: http(),
491
+ * })
492
+ *
493
+ * const isBurned = await Actions.accessKey.isWitnessBurned(client, {
494
+ * account: '0x...',
495
+ * witness: '0x...',
496
+ * })
497
+ * ```
498
+ *
499
+ * @param client - Client.
500
+ * @param parameters - Parameters.
501
+ * @returns Whether the witness has been burned.
502
+ */
503
+ export async function isWitnessBurned(client, parameters) {
504
+ const { account: account_ = client.account, witness, ...rest } = parameters;
505
+ if (!account_)
506
+ throw new Error('account is required.');
507
+ const account = parseAccount(account_);
508
+ return readContract(client, {
509
+ ...rest,
510
+ account: null,
511
+ ...isWitnessBurned.call({ account: account.address, witness }),
512
+ });
513
+ }
514
+ (function (isWitnessBurned) {
515
+ /**
516
+ * Defines a call to the `isKeyAuthorizationWitnessBurned` function.
517
+ *
518
+ * @param args - Arguments.
519
+ * @returns The call.
520
+ */
521
+ function call(args) {
522
+ const { account, witness } = args;
523
+ return defineCall({
524
+ address: Addresses.accountKeychain,
525
+ abi: Abis.accountKeychain,
526
+ functionName: 'isKeyAuthorizationWitnessBurned',
527
+ args: [account, witness],
528
+ });
529
+ }
530
+ isWitnessBurned.call = call;
531
+ })(isWitnessBurned || (isWitnessBurned = {}));
137
532
  /**
138
533
  * Revokes an authorized access key.
139
534
  *
@@ -262,6 +657,47 @@ export async function revokeSync(client, parameters) {
262
657
  receipt,
263
658
  };
264
659
  }
660
+ /**
661
+ * Signs a key authorization for an access key.
662
+ *
663
+ * @example
664
+ * ```ts
665
+ * import { generatePrivateKey } from 'viem/accounts'
666
+ * import { Account, Actions } from 'viem/tempo'
667
+ *
668
+ * const account = Account.from({ privateKey: '0x...' })
669
+ * const accessKey = Account.fromP256(generatePrivateKey(), {
670
+ * access: account,
671
+ * })
672
+ *
673
+ * const keyAuthorization = await Actions.accessKey.signAuthorization(
674
+ * client,
675
+ * {
676
+ * account,
677
+ * accessKey,
678
+ * expiry: Math.floor((Date.now() + 30_000) / 1000),
679
+ * },
680
+ * )
681
+ * ```
682
+ *
683
+ * @param client - Client.
684
+ * @param parameters - Parameters.
685
+ * @returns The signed key authorization.
686
+ */
687
+ export async function signAuthorization(client, parameters) {
688
+ const { accessKey, chainId = client.chain?.id, ...rest } = parameters;
689
+ const account_ = rest.account ?? client.account;
690
+ if (!account_)
691
+ throw new Error('account is required.');
692
+ if (!chainId)
693
+ throw new Error('chainId is required.');
694
+ const parsed = parseAccount(account_);
695
+ return signKeyAuthorization(parsed, {
696
+ chainId: BigInt(chainId),
697
+ key: accessKey,
698
+ ...rest,
699
+ });
700
+ }
265
701
  /**
266
702
  * Updates the spending limit for a specific token on an authorized access key.
267
703
  *
@@ -402,7 +838,12 @@ export async function updateLimitSync(client, parameters) {
402
838
  };
403
839
  }
404
840
  /**
405
- * Gets access key information.
841
+ * Watches for admin key authorization events.
842
+ *
843
+ * Emitted when an admin key is authorized (see {@link authorize} with
844
+ * `admin: true`).
845
+ *
846
+ * [TIP-1049](https://tips.sh/1049)
406
847
  *
407
848
  * @example
408
849
  * ```ts
@@ -415,55 +856,35 @@ export async function updateLimitSync(client, parameters) {
415
856
  * transport: http(),
416
857
  * })
417
858
  *
418
- * const key = await Actions.accessKey.getMetadata(client, {
419
- * account: '0x...',
420
- * accessKey: '0x...',
859
+ * const unwatch = Actions.accessKey.watchAdminAuthorized(client, {
860
+ * onAuthorized: (args, log) => {
861
+ * console.log('Admin key authorized:', args)
862
+ * },
421
863
  * })
422
864
  * ```
423
865
  *
424
866
  * @param client - Client.
425
867
  * @param parameters - Parameters.
426
- * @returns The key information.
868
+ * @returns A function to unsubscribe from the event.
427
869
  */
428
- export async function getMetadata(client, parameters) {
429
- const { account: account_ = client.account, accessKey, ...rest } = parameters;
430
- if (!account_)
431
- throw new Error('account is required.');
432
- const account = parseAccount(account_);
433
- const result = await readContract(client, {
870
+ export function watchAdminAuthorized(client, parameters) {
871
+ const { onAuthorized, ...rest } = parameters;
872
+ return watchContractEvent(client, {
434
873
  ...rest,
435
- account: null,
436
- ...getMetadata.call({ account: account.address, accessKey }),
874
+ address: Addresses.accountKeychain,
875
+ abi: Abis.accountKeychain,
876
+ eventName: 'AdminKeyAuthorized',
877
+ onLogs: (logs) => {
878
+ for (const log of logs)
879
+ onAuthorized(log.args, log);
880
+ },
881
+ strict: true,
437
882
  });
438
- return {
439
- address: result.keyId,
440
- keyType: signatureTypes[result.signatureType] ??
441
- 'secp256k1',
442
- expiry: result.expiry,
443
- spendPolicy: spendPolicies[`${result.enforceLimits}`],
444
- isRevoked: result.isRevoked,
445
- };
446
883
  }
447
- (function (getMetadata) {
448
- /**
449
- * Defines a call to the `getKey` function.
450
- *
451
- * @param args - Arguments.
452
- * @returns The call.
453
- */
454
- function call(args) {
455
- const { account, accessKey } = args;
456
- return defineCall({
457
- address: Addresses.accountKeychain,
458
- abi: Abis.accountKeychain,
459
- functionName: 'getKey',
460
- args: [account, resolveAccessKeyAddress(accessKey)],
461
- });
462
- }
463
- getMetadata.call = call;
464
- })(getMetadata || (getMetadata = {}));
465
884
  /**
466
- * Gets the remaining spending limit for a key-token pair.
885
+ * Watches for key-authorization witness events.
886
+ *
887
+ * Emitted when a key is authorized with a `witness` (see {@link authorize}).
467
888
  *
468
889
  * @example
469
890
  * ```ts
@@ -476,118 +897,131 @@ export async function getMetadata(client, parameters) {
476
897
  * transport: http(),
477
898
  * })
478
899
  *
479
- * const { remaining, periodEnd } = await Actions.accessKey.getRemainingLimit(client, {
480
- * account: '0x...',
481
- * accessKey: '0x...',
482
- * token: '0x...',
900
+ * const unwatch = Actions.accessKey.watchWitness(client, {
901
+ * onWitness: (args, log) => {
902
+ * console.log('Witness used:', args)
903
+ * },
483
904
  * })
484
- *
485
- * console.log(remaining, periodEnd)
486
905
  * ```
487
906
  *
488
907
  * @param client - Client.
489
908
  * @param parameters - Parameters.
490
- * @returns The remaining spending amount and period end timestamp.
909
+ * @returns A function to unsubscribe from the event.
491
910
  */
492
- export async function getRemainingLimit(client, parameters) {
493
- const { account: account_ = client.account, accessKey, token, ...rest } = parameters;
494
- if (!account_)
495
- throw new Error('account is required.');
496
- const account = parseAccount(account_);
497
- // TODO: remove pre-t3 branch once mainnet is on t3.
498
- const hardfork = client.chain?.hardfork;
499
- if (hardfork && Hardfork.lt(hardfork, 't3')) {
500
- const remaining = await readContract(client, {
501
- ...rest,
502
- ...getRemainingLimit.call({ account: account.address, accessKey, token }),
503
- });
504
- return { remaining, periodEnd: undefined };
505
- }
506
- const [remaining, periodEnd] = await readContract(client, {
911
+ export function watchWitness(client, parameters) {
912
+ const { onWitness, ...rest } = parameters;
913
+ return watchContractEvent(client, {
507
914
  ...rest,
508
- ...getRemainingLimit.callWithPeriod({
509
- account: account.address,
510
- accessKey,
511
- token,
512
- }),
915
+ address: Addresses.accountKeychain,
916
+ abi: Abis.accountKeychain,
917
+ eventName: 'KeyAuthorizationWitness',
918
+ onLogs: (logs) => {
919
+ for (const log of logs)
920
+ onWitness(log.args, log);
921
+ },
922
+ strict: true,
513
923
  });
514
- return { remaining, periodEnd };
515
924
  }
516
- (function (getRemainingLimit) {
517
- /**
518
- * Defines a call to the `getRemainingLimit` function (pre-T3).
519
- *
520
- * @param args - Arguments.
521
- * @returns The call.
522
- */
523
- function call(args) {
524
- const { account, accessKey, token } = args;
525
- return defineCall({
526
- address: Addresses.accountKeychain,
527
- abi: Abis.accountKeychain,
528
- functionName: 'getRemainingLimit',
529
- args: [account, resolveAccessKeyAddress(accessKey), token],
530
- });
531
- }
532
- getRemainingLimit.call = call;
533
- /**
534
- * Defines a call to the `getRemainingLimitWithPeriod` function (T3+).
535
- *
536
- * @param args - Arguments.
537
- * @returns The call.
538
- */
539
- function callWithPeriod(args) {
540
- const { account, accessKey, token } = args;
541
- return defineCall({
542
- address: Addresses.accountKeychain,
543
- abi: Abis.accountKeychain,
544
- functionName: 'getRemainingLimitWithPeriod',
545
- args: [account, resolveAccessKeyAddress(accessKey), token],
546
- });
547
- }
548
- getRemainingLimit.callWithPeriod = callWithPeriod;
549
- })(getRemainingLimit || (getRemainingLimit = {}));
550
925
  /**
551
- * Signs a key authorization for an access key.
926
+ * Watches for key-authorization witness burned events.
927
+ *
928
+ * Emitted when a witness is burned (see {@link burnWitness}).
552
929
  *
553
930
  * @example
554
931
  * ```ts
555
- * import { generatePrivateKey } from 'viem/accounts'
556
- * import { Account, Actions } from 'viem/tempo'
932
+ * import { createClient, http } from 'viem'
933
+ * import { tempo } from 'viem/chains'
934
+ * import { Actions } from 'viem/tempo'
557
935
  *
558
- * const account = Account.from({ privateKey: '0x...' })
559
- * const accessKey = Account.fromP256(generatePrivateKey(), {
560
- * access: account,
936
+ * const client = createClient({
937
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
938
+ * transport: http(),
561
939
  * })
562
940
  *
563
- * const keyAuthorization = await Actions.accessKey.signAuthorization(
564
- * client,
565
- * {
566
- * account,
567
- * accessKey,
568
- * expiry: Math.floor((Date.now() + 30_000) / 1000),
941
+ * const unwatch = Actions.accessKey.watchWitnessBurned(client, {
942
+ * onBurned: (args, log) => {
943
+ * console.log('Witness burned:', args)
569
944
  * },
570
- * )
945
+ * })
571
946
  * ```
572
947
  *
573
948
  * @param client - Client.
574
949
  * @param parameters - Parameters.
575
- * @returns The signed key authorization.
950
+ * @returns A function to unsubscribe from the event.
576
951
  */
577
- export async function signAuthorization(client, parameters) {
578
- const { accessKey, chainId = client.chain?.id, ...rest } = parameters;
579
- const account_ = rest.account ?? client.account;
580
- if (!account_)
581
- throw new Error('account is required.');
582
- if (!chainId)
583
- throw new Error('chainId is required.');
584
- const parsed = parseAccount(account_);
585
- return signKeyAuthorization(parsed, {
586
- chainId: BigInt(chainId),
587
- key: accessKey,
952
+ export function watchWitnessBurned(client, parameters) {
953
+ const { onBurned, ...rest } = parameters;
954
+ return watchContractEvent(client, {
955
+ ...rest,
956
+ address: Addresses.accountKeychain,
957
+ abi: Abis.accountKeychain,
958
+ eventName: 'KeyAuthorizationWitnessBurned',
959
+ onLogs: (logs) => {
960
+ for (const log of logs)
961
+ onBurned(log.args, log);
962
+ },
963
+ strict: true,
964
+ });
965
+ }
966
+ /**
967
+ * Verifies that a keychain signature was produced by an active access key
968
+ * for the expected account.
969
+ *
970
+ * By default (`admin: true`), returns `true` only if the signature was
971
+ * produced by the account's root key or an active admin access key. Set
972
+ * `admin: false` to accept any active access key.
973
+ *
974
+ * Returns `false` for account mismatches, unknown, revoked, or expired
975
+ * access keys. [TIP-1049](https://tips.sh/1049)
976
+ *
977
+ * @example
978
+ * ```ts
979
+ * import { createClient, http } from 'viem'
980
+ * import { tempo } from 'viem/chains'
981
+ * import { Actions } from 'viem/tempo'
982
+ *
983
+ * const client = createClient({
984
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
985
+ * transport: http(),
986
+ * })
987
+ *
988
+ * const valid = await Actions.accessKey.verifyHash(client, {
989
+ * account: '0x...',
990
+ * hash: '0x...',
991
+ * signature: '0x...',
992
+ * })
993
+ * ```
994
+ *
995
+ * @param client - Client.
996
+ * @param parameters - Parameters.
997
+ * @returns Whether the keychain signature is valid for the account.
998
+ */
999
+ export async function verifyHash(client, parameters) {
1000
+ const { account, admin, hash, signature, ...rest } = parameters;
1001
+ return readContract(client, {
588
1002
  ...rest,
1003
+ ...verifyHash.call({ account, admin, hash, signature }),
589
1004
  });
590
1005
  }
1006
+ (function (verifyHash) {
1007
+ /**
1008
+ * Defines a call to `verifyKeychain` or `verifyKeychainAdmin` on the
1009
+ * Signature Verifier precompile (controlled by `admin`).
1010
+ *
1011
+ * @param args - Arguments.
1012
+ * @returns The call.
1013
+ */
1014
+ function call(args) {
1015
+ const { account, admin = true, hash, signature } = args;
1016
+ return defineCall({
1017
+ address: Addresses.signatureVerifier,
1018
+ abi: Abis.signatureVerifier,
1019
+ functionName: admin ? 'verifyKeychainAdmin' : 'verifyKeychain',
1020
+ args: [account, hash, signature],
1021
+ });
1022
+ }
1023
+ verifyHash.call = call;
1024
+ })(verifyHash || (verifyHash = {}));
591
1025
  /** @internal */
592
1026
  function resolveAccessKeyAddress(accessKey) {
593
1027
  if (typeof accessKey === 'string')