viem 2.51.2 → 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 +18 -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 +239 -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 -127
  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 +1003 -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,54 +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
- ...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,
436
882
  });
437
- return {
438
- address: result.keyId,
439
- keyType: signatureTypes[result.signatureType] ??
440
- 'secp256k1',
441
- expiry: result.expiry,
442
- spendPolicy: spendPolicies[`${result.enforceLimits}`],
443
- isRevoked: result.isRevoked,
444
- };
445
883
  }
446
- (function (getMetadata) {
447
- /**
448
- * Defines a call to the `getKey` function.
449
- *
450
- * @param args - Arguments.
451
- * @returns The call.
452
- */
453
- function call(args) {
454
- const { account, accessKey } = args;
455
- return defineCall({
456
- address: Addresses.accountKeychain,
457
- abi: Abis.accountKeychain,
458
- functionName: 'getKey',
459
- args: [account, resolveAccessKeyAddress(accessKey)],
460
- });
461
- }
462
- getMetadata.call = call;
463
- })(getMetadata || (getMetadata = {}));
464
884
  /**
465
- * 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}).
466
888
  *
467
889
  * @example
468
890
  * ```ts
@@ -475,118 +897,131 @@ export async function getMetadata(client, parameters) {
475
897
  * transport: http(),
476
898
  * })
477
899
  *
478
- * const { remaining, periodEnd } = await Actions.accessKey.getRemainingLimit(client, {
479
- * account: '0x...',
480
- * accessKey: '0x...',
481
- * token: '0x...',
900
+ * const unwatch = Actions.accessKey.watchWitness(client, {
901
+ * onWitness: (args, log) => {
902
+ * console.log('Witness used:', args)
903
+ * },
482
904
  * })
483
- *
484
- * console.log(remaining, periodEnd)
485
905
  * ```
486
906
  *
487
907
  * @param client - Client.
488
908
  * @param parameters - Parameters.
489
- * @returns The remaining spending amount and period end timestamp.
909
+ * @returns A function to unsubscribe from the event.
490
910
  */
491
- export async function getRemainingLimit(client, parameters) {
492
- const { account: account_ = client.account, accessKey, token, ...rest } = parameters;
493
- if (!account_)
494
- throw new Error('account is required.');
495
- const account = parseAccount(account_);
496
- // TODO: remove pre-t3 branch once mainnet is on t3.
497
- const hardfork = client.chain?.hardfork;
498
- if (hardfork && Hardfork.lt(hardfork, 't3')) {
499
- const remaining = await readContract(client, {
500
- ...rest,
501
- ...getRemainingLimit.call({ account: account.address, accessKey, token }),
502
- });
503
- return { remaining, periodEnd: undefined };
504
- }
505
- const [remaining, periodEnd] = await readContract(client, {
911
+ export function watchWitness(client, parameters) {
912
+ const { onWitness, ...rest } = parameters;
913
+ return watchContractEvent(client, {
506
914
  ...rest,
507
- ...getRemainingLimit.callWithPeriod({
508
- account: account.address,
509
- accessKey,
510
- token,
511
- }),
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,
512
923
  });
513
- return { remaining, periodEnd };
514
924
  }
515
- (function (getRemainingLimit) {
516
- /**
517
- * Defines a call to the `getRemainingLimit` function (pre-T3).
518
- *
519
- * @param args - Arguments.
520
- * @returns The call.
521
- */
522
- function call(args) {
523
- const { account, accessKey, token } = args;
524
- return defineCall({
525
- address: Addresses.accountKeychain,
526
- abi: Abis.accountKeychain,
527
- functionName: 'getRemainingLimit',
528
- args: [account, resolveAccessKeyAddress(accessKey), token],
529
- });
530
- }
531
- getRemainingLimit.call = call;
532
- /**
533
- * Defines a call to the `getRemainingLimitWithPeriod` function (T3+).
534
- *
535
- * @param args - Arguments.
536
- * @returns The call.
537
- */
538
- function callWithPeriod(args) {
539
- const { account, accessKey, token } = args;
540
- return defineCall({
541
- address: Addresses.accountKeychain,
542
- abi: Abis.accountKeychain,
543
- functionName: 'getRemainingLimitWithPeriod',
544
- args: [account, resolveAccessKeyAddress(accessKey), token],
545
- });
546
- }
547
- getRemainingLimit.callWithPeriod = callWithPeriod;
548
- })(getRemainingLimit || (getRemainingLimit = {}));
549
925
  /**
550
- * 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}).
551
929
  *
552
930
  * @example
553
931
  * ```ts
554
- * import { generatePrivateKey } from 'viem/accounts'
555
- * import { Account, Actions } from 'viem/tempo'
932
+ * import { createClient, http } from 'viem'
933
+ * import { tempo } from 'viem/chains'
934
+ * import { Actions } from 'viem/tempo'
556
935
  *
557
- * const account = Account.from({ privateKey: '0x...' })
558
- * const accessKey = Account.fromP256(generatePrivateKey(), {
559
- * access: account,
936
+ * const client = createClient({
937
+ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }),
938
+ * transport: http(),
560
939
  * })
561
940
  *
562
- * const keyAuthorization = await Actions.accessKey.signAuthorization(
563
- * client,
564
- * {
565
- * account,
566
- * accessKey,
567
- * 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)
568
944
  * },
569
- * )
945
+ * })
570
946
  * ```
571
947
  *
572
948
  * @param client - Client.
573
949
  * @param parameters - Parameters.
574
- * @returns The signed key authorization.
950
+ * @returns A function to unsubscribe from the event.
575
951
  */
576
- export async function signAuthorization(client, parameters) {
577
- const { accessKey, chainId = client.chain?.id, ...rest } = parameters;
578
- const account_ = rest.account ?? client.account;
579
- if (!account_)
580
- throw new Error('account is required.');
581
- if (!chainId)
582
- throw new Error('chainId is required.');
583
- const parsed = parseAccount(account_);
584
- return signKeyAuthorization(parsed, {
585
- chainId: BigInt(chainId),
586
- 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, {
587
1002
  ...rest,
1003
+ ...verifyHash.call({ account, admin, hash, signature }),
588
1004
  });
589
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 = {}));
590
1025
  /** @internal */
591
1026
  function resolveAccessKeyAddress(accessKey) {
592
1027
  if (typeof accessKey === 'string')