viem 2.57.8 → 2.57.10

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 (138) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/_cjs/clients/createClient.js +49 -4
  3. package/_cjs/clients/createClient.js.map +1 -1
  4. package/_cjs/clients/transports/fallback.js +2 -2
  5. package/_cjs/clients/transports/fallback.js.map +1 -1
  6. package/_cjs/errors/version.js +1 -1
  7. package/_cjs/errors/version.js.map +1 -1
  8. package/_cjs/experimental/erc7821/actions/supportsExecutionMode.js +1 -1
  9. package/_cjs/experimental/erc7821/actions/supportsExecutionMode.js.map +1 -1
  10. package/_cjs/op-stack/actions/getPortalVersion.js +4 -1
  11. package/_cjs/op-stack/actions/getPortalVersion.js.map +1 -1
  12. package/_cjs/tempo/Abis.js +84 -15
  13. package/_cjs/tempo/Abis.js.map +1 -1
  14. package/_cjs/tempo/Account.js +13 -11
  15. package/_cjs/tempo/Account.js.map +1 -1
  16. package/_cjs/tempo/Addresses.js +3 -3
  17. package/_cjs/tempo/Addresses.js.map +1 -1
  18. package/_cjs/tempo/Decorator.js +4 -0
  19. package/_cjs/tempo/Decorator.js.map +1 -1
  20. package/_cjs/tempo/ExecutionError.js +25 -2
  21. package/_cjs/tempo/ExecutionError.js.map +1 -1
  22. package/_cjs/tempo/Hardfork.js +12 -1
  23. package/_cjs/tempo/Hardfork.js.map +1 -1
  24. package/_cjs/tempo/Selectors.js +4 -2
  25. package/_cjs/tempo/Selectors.js.map +1 -1
  26. package/_cjs/tempo/accounts/Config.js +4 -2
  27. package/_cjs/tempo/accounts/Config.js.map +1 -1
  28. package/_cjs/tempo/accounts/Operation.js +2 -2
  29. package/_cjs/tempo/accounts/Operation.js.map +1 -1
  30. package/_cjs/tempo/actions/accessKey.js +1 -0
  31. package/_cjs/tempo/actions/accessKey.js.map +1 -1
  32. package/_cjs/tempo/actions/accounts.js +122 -7
  33. package/_cjs/tempo/actions/accounts.js.map +1 -1
  34. package/_cjs/tempo/chainConfig.js +29 -2
  35. package/_cjs/tempo/chainConfig.js.map +1 -1
  36. package/_cjs/tempo/internal/relay/accounts.js +46 -5
  37. package/_cjs/tempo/internal/relay/accounts.js.map +1 -1
  38. package/_cjs/tempo/internal/relay/feePayer.js +4 -4
  39. package/_cjs/tempo/internal/relay/feePayer.js.map +1 -1
  40. package/_cjs/utils/promise/withRetry.js +5 -1
  41. package/_cjs/utils/promise/withRetry.js.map +1 -1
  42. package/_esm/clients/createClient.js +57 -4
  43. package/_esm/clients/createClient.js.map +1 -1
  44. package/_esm/clients/transports/fallback.js +2 -2
  45. package/_esm/clients/transports/fallback.js.map +1 -1
  46. package/_esm/errors/version.js +1 -1
  47. package/_esm/errors/version.js.map +1 -1
  48. package/_esm/experimental/erc7821/actions/supportsExecutionMode.js +2 -1
  49. package/_esm/experimental/erc7821/actions/supportsExecutionMode.js.map +1 -1
  50. package/_esm/op-stack/actions/getPortalVersion.js +4 -1
  51. package/_esm/op-stack/actions/getPortalVersion.js.map +1 -1
  52. package/_esm/tempo/Abis.js +84 -15
  53. package/_esm/tempo/Abis.js.map +1 -1
  54. package/_esm/tempo/Account.js +18 -12
  55. package/_esm/tempo/Account.js.map +1 -1
  56. package/_esm/tempo/Addresses.js +3 -3
  57. package/_esm/tempo/Addresses.js.map +1 -1
  58. package/_esm/tempo/Decorator.js +4 -0
  59. package/_esm/tempo/Decorator.js.map +1 -1
  60. package/_esm/tempo/ExecutionError.js +25 -2
  61. package/_esm/tempo/ExecutionError.js.map +1 -1
  62. package/_esm/tempo/Hardfork.js +17 -2
  63. package/_esm/tempo/Hardfork.js.map +1 -1
  64. package/_esm/tempo/Selectors.js +3 -1
  65. package/_esm/tempo/Selectors.js.map +1 -1
  66. package/_esm/tempo/accounts/Config.js +5 -3
  67. package/_esm/tempo/accounts/Config.js.map +1 -1
  68. package/_esm/tempo/accounts/Operation.js +2 -2
  69. package/_esm/tempo/accounts/Operation.js.map +1 -1
  70. package/_esm/tempo/actions/accessKey.js +1 -0
  71. package/_esm/tempo/actions/accessKey.js.map +1 -1
  72. package/_esm/tempo/actions/accounts.js +279 -8
  73. package/_esm/tempo/actions/accounts.js.map +1 -1
  74. package/_esm/tempo/chainConfig.js +33 -3
  75. package/_esm/tempo/chainConfig.js.map +1 -1
  76. package/_esm/tempo/internal/relay/accounts.js +50 -5
  77. package/_esm/tempo/internal/relay/accounts.js.map +1 -1
  78. package/_esm/tempo/internal/relay/feePayer.js +4 -4
  79. package/_esm/tempo/internal/relay/feePayer.js.map +1 -1
  80. package/_esm/utils/promise/withRetry.js +6 -1
  81. package/_esm/utils/promise/withRetry.js.map +1 -1
  82. package/_types/clients/createClient.d.ts +30 -0
  83. package/_types/clients/createClient.d.ts.map +1 -1
  84. package/_types/clients/transports/fallback.d.ts.map +1 -1
  85. package/_types/errors/version.d.ts +1 -1
  86. package/_types/errors/version.d.ts.map +1 -1
  87. package/_types/experimental/erc7821/actions/supportsExecutionMode.d.ts.map +1 -1
  88. package/_types/op-stack/actions/getPortalVersion.d.ts.map +1 -1
  89. package/_types/tempo/Abis.d.ts +621 -307
  90. package/_types/tempo/Abis.d.ts.map +1 -1
  91. package/_types/tempo/Account.d.ts +24 -4
  92. package/_types/tempo/Account.d.ts.map +1 -1
  93. package/_types/tempo/Addresses.d.ts +3 -3
  94. package/_types/tempo/Addresses.d.ts.map +1 -1
  95. package/_types/tempo/Decorator.d.ts +104 -0
  96. package/_types/tempo/Decorator.d.ts.map +1 -1
  97. package/_types/tempo/ExecutionError.d.ts.map +1 -1
  98. package/_types/tempo/Hardfork.d.ts +6 -2
  99. package/_types/tempo/Hardfork.d.ts.map +1 -1
  100. package/_types/tempo/Selectors.d.ts +3 -1
  101. package/_types/tempo/Selectors.d.ts.map +1 -1
  102. package/_types/tempo/Transaction.d.ts +2 -2
  103. package/_types/tempo/Transaction.d.ts.map +1 -1
  104. package/_types/tempo/actions/accessKey.d.ts +3 -2
  105. package/_types/tempo/actions/accessKey.d.ts.map +1 -1
  106. package/_types/tempo/actions/accounts.d.ts +594 -7
  107. package/_types/tempo/actions/accounts.d.ts.map +1 -1
  108. package/_types/tempo/actions/channel.d.ts +42 -0
  109. package/_types/tempo/actions/channel.d.ts.map +1 -1
  110. package/_types/tempo/actions/reward.d.ts +14 -0
  111. package/_types/tempo/actions/reward.d.ts.map +1 -1
  112. package/_types/tempo/actions/token.d.ts +105 -0
  113. package/_types/tempo/actions/token.d.ts.map +1 -1
  114. package/_types/tempo/chainConfig.d.ts.map +1 -1
  115. package/_types/tempo/internal/relay/accounts.d.ts.map +1 -1
  116. package/_types/utils/promise/withRetry.d.ts.map +1 -1
  117. package/clients/createClient.ts +103 -5
  118. package/clients/transports/fallback.ts +8 -5
  119. package/errors/version.ts +1 -1
  120. package/experimental/erc7821/actions/supportsExecutionMode.ts +2 -1
  121. package/op-stack/actions/getPortalVersion.ts +4 -1
  122. package/package.json +2 -2
  123. package/tempo/Abis.ts +84 -15
  124. package/tempo/Account.ts +52 -16
  125. package/tempo/Addresses.ts +4 -4
  126. package/tempo/Decorator.ts +116 -0
  127. package/tempo/ExecutionError.ts +28 -2
  128. package/tempo/Hardfork.ts +16 -2
  129. package/tempo/Selectors.ts +4 -2
  130. package/tempo/Transaction.ts +2 -2
  131. package/tempo/accounts/Config.ts +5 -3
  132. package/tempo/accounts/Operation.ts +2 -2
  133. package/tempo/actions/accessKey.ts +3 -2
  134. package/tempo/actions/accounts.ts +394 -10
  135. package/tempo/chainConfig.ts +41 -3
  136. package/tempo/internal/relay/accounts.ts +62 -5
  137. package/tempo/internal/relay/feePayer.ts +4 -4
  138. package/utils/promise/withRetry.ts +7 -1
package/tempo/Abis.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // Generated with `pnpm gen:tempo-abis`. Do not modify manually.
2
- // Source: tempoxyz/tempo@6ef1f812c9ddcbe90a88ada73944012520942d26
2
+ // Source: tempoxyz/tempo@e539a1dac2921670585a08215e516d8b98aa527a
3
3
 
4
4
  export const accountKeychain = [
5
5
  {
@@ -444,7 +444,7 @@ export const addressRegistry = [
444
444
  { name: 'VirtualAddressUnregistered', type: 'error', inputs: [] },
445
445
  ] as const
446
446
 
447
- export const nativeMultisig = [
447
+ export const configurableAccount = [
448
448
  {
449
449
  name: 'deriveAccount',
450
450
  type: 'function',
@@ -505,7 +505,24 @@ export const nativeMultisig = [
505
505
  outputs: [],
506
506
  },
507
507
  {
508
- name: 'MultisigConfigUpdated',
508
+ name: 'upgradeAccount',
509
+ type: 'function',
510
+ stateMutability: 'nonpayable',
511
+ inputs: [
512
+ { type: 'uint8', name: 'threshold' },
513
+ {
514
+ type: 'tuple[]',
515
+ name: 'owners',
516
+ components: [
517
+ { type: 'address', name: 'owner' },
518
+ { type: 'uint8', name: 'weight' },
519
+ ],
520
+ },
521
+ ],
522
+ outputs: [{ type: 'bytes32', name: 'commitment' }],
523
+ },
524
+ {
525
+ name: 'ConfigurableAccountConfigUpdated',
509
526
  type: 'event',
510
527
  inputs: [
511
528
  { type: 'address', name: 'account', indexed: true },
@@ -522,15 +539,37 @@ export const nativeMultisig = [
522
539
  },
523
540
  ],
524
541
  },
542
+ {
543
+ name: 'AccountUpgraded',
544
+ type: 'event',
545
+ inputs: [
546
+ { type: 'address', name: 'account', indexed: true },
547
+ { type: 'bytes32', name: 'commitment', indexed: true },
548
+ { type: 'bytes32', name: 'salt' },
549
+ { type: 'uint8', name: 'threshold' },
550
+ {
551
+ type: 'tuple[]',
552
+ name: 'owners',
553
+ components: [
554
+ { type: 'address', name: 'owner' },
555
+ { type: 'uint8', name: 'weight' },
556
+ ],
557
+ },
558
+ ],
559
+ },
525
560
  { name: 'InvalidAccount', type: 'error', inputs: [] },
526
561
  { name: 'InvalidConfig', type: 'error', inputs: [] },
527
562
  { name: 'InvalidThreshold', type: 'error', inputs: [] },
528
- { name: 'InvalidMultisigOwner', type: 'error', inputs: [] },
563
+ { name: 'InvalidConfigurableAccountOwner', type: 'error', inputs: [] },
529
564
  { name: 'InvalidWeight', type: 'error', inputs: [] },
530
565
  { name: 'TooManyOwners', type: 'error', inputs: [] },
531
566
  { name: 'DuplicateOwner', type: 'error', inputs: [] },
532
567
  { name: 'InvalidOwnerOrder', type: 'error', inputs: [] },
533
- { name: 'UnauthorizedMultisigCaller', type: 'error', inputs: [] },
568
+ { name: 'UnauthorizedConfigurableAccountCaller', type: 'error', inputs: [] },
569
+ { name: 'PrimitiveRootRequired', type: 'error', inputs: [] },
570
+ { name: 'UpgradeMustBeOnlyCall', type: 'error', inputs: [] },
571
+ { name: 'AccountAlreadyConfigurable', type: 'error', inputs: [] },
572
+ { name: 'AccountHasCode', type: 'error', inputs: [] },
534
573
  ] as const
535
574
 
536
575
  export const currentCommittee = [
@@ -705,6 +744,17 @@ export const signatureVerifier = [
705
744
  ],
706
745
  outputs: [{ type: 'bool' }],
707
746
  },
747
+ {
748
+ name: 'verifyConfigurableAccount',
749
+ type: 'function',
750
+ stateMutability: 'view',
751
+ inputs: [
752
+ { type: 'address', name: 'account' },
753
+ { type: 'bytes32', name: 'hash' },
754
+ { type: 'bytes', name: 'signature' },
755
+ ],
756
+ outputs: [{ type: 'bool' }],
757
+ },
708
758
  { name: 'InvalidFormat', type: 'error', inputs: [] },
709
759
  { name: 'InvalidSignature', type: 'error', inputs: [] },
710
760
  ] as const
@@ -1710,6 +1760,11 @@ export const tip20ChannelReserve = [
1710
1760
  { name: 'CaptureAmountInvalid', type: 'error', inputs: [] },
1711
1761
  { name: 'CloseNotReady', type: 'error', inputs: [] },
1712
1762
  { name: 'DepositOverflow', type: 'error', inputs: [] },
1763
+ {
1764
+ name: 'RootKeyRetired',
1765
+ type: 'error',
1766
+ inputs: [{ type: 'address', name: 'account' }],
1767
+ },
1713
1768
  ] as const
1714
1769
 
1715
1770
  export const tip20Factory = [
@@ -2314,6 +2369,11 @@ export const tip20 = [
2314
2369
  { name: 'InvalidSignature', type: 'error', inputs: [] },
2315
2370
  { name: 'LogoURITooLong', type: 'error', inputs: [] },
2316
2371
  { name: 'InvalidLogoURI', type: 'error', inputs: [] },
2372
+ {
2373
+ name: 'RootKeyRetired',
2374
+ type: 'error',
2375
+ inputs: [{ type: 'address', name: 'account' }],
2376
+ },
2317
2377
  {
2318
2378
  name: 'hasRole',
2319
2379
  type: 'function',
@@ -9861,10 +9921,10 @@ export const directPropAmm = [
9861
9921
  export const core = [
9862
9922
  ...accountKeychain,
9863
9923
  ...addressRegistry,
9924
+ ...configurableAccount,
9864
9925
  ...currentCommittee,
9865
9926
  ...feeAmm,
9866
9927
  ...feeManager,
9867
- ...nativeMultisig,
9868
9928
  ...nonce,
9869
9929
  ...receivePolicyGuard,
9870
9930
  ...signatureVerifier,
@@ -9946,6 +10006,19 @@ export const coreErrors = [
9946
10006
  { name: 'InvalidMasterAddress', type: 'error', inputs: [] },
9947
10007
  { name: 'ProofOfWorkFailed', type: 'error', inputs: [] },
9948
10008
  { name: 'VirtualAddressUnregistered', type: 'error', inputs: [] },
10009
+ { name: 'InvalidAccount', type: 'error', inputs: [] },
10010
+ { name: 'InvalidConfig', type: 'error', inputs: [] },
10011
+ { name: 'InvalidThreshold', type: 'error', inputs: [] },
10012
+ { name: 'InvalidConfigurableAccountOwner', type: 'error', inputs: [] },
10013
+ { name: 'InvalidWeight', type: 'error', inputs: [] },
10014
+ { name: 'TooManyOwners', type: 'error', inputs: [] },
10015
+ { name: 'DuplicateOwner', type: 'error', inputs: [] },
10016
+ { name: 'InvalidOwnerOrder', type: 'error', inputs: [] },
10017
+ { name: 'UnauthorizedConfigurableAccountCaller', type: 'error', inputs: [] },
10018
+ { name: 'PrimitiveRootRequired', type: 'error', inputs: [] },
10019
+ { name: 'UpgradeMustBeOnlyCall', type: 'error', inputs: [] },
10020
+ { name: 'AccountAlreadyConfigurable', type: 'error', inputs: [] },
10021
+ { name: 'AccountHasCode', type: 'error', inputs: [] },
9949
10022
  { name: 'Unauthorized', type: 'error', inputs: [] },
9950
10023
  { name: 'IdenticalAddresses', type: 'error', inputs: [] },
9951
10024
  { name: 'InvalidToken', type: 'error', inputs: [] },
@@ -9956,15 +10029,6 @@ export const coreErrors = [
9956
10029
  { name: 'InvalidSwapCalculation', type: 'error', inputs: [] },
9957
10030
  { name: 'InsufficientFeeTokenBalance', type: 'error', inputs: [] },
9958
10031
  { name: 'CannotChangeWithinBlock', type: 'error', inputs: [] },
9959
- { name: 'InvalidAccount', type: 'error', inputs: [] },
9960
- { name: 'InvalidConfig', type: 'error', inputs: [] },
9961
- { name: 'InvalidThreshold', type: 'error', inputs: [] },
9962
- { name: 'InvalidMultisigOwner', type: 'error', inputs: [] },
9963
- { name: 'InvalidWeight', type: 'error', inputs: [] },
9964
- { name: 'TooManyOwners', type: 'error', inputs: [] },
9965
- { name: 'DuplicateOwner', type: 'error', inputs: [] },
9966
- { name: 'InvalidOwnerOrder', type: 'error', inputs: [] },
9967
- { name: 'UnauthorizedMultisigCaller', type: 'error', inputs: [] },
9968
10032
  { name: 'ProtocolNonceNotSupported', type: 'error', inputs: [] },
9969
10033
  { name: 'InvalidNonceKey', type: 'error', inputs: [] },
9970
10034
  { name: 'NonceOverflow', type: 'error', inputs: [] },
@@ -10026,6 +10090,11 @@ export const coreErrors = [
10026
10090
  { name: 'PermitExpired', type: 'error', inputs: [] },
10027
10091
  { name: 'LogoURITooLong', type: 'error', inputs: [] },
10028
10092
  { name: 'InvalidLogoURI', type: 'error', inputs: [] },
10093
+ {
10094
+ name: 'RootKeyRetired',
10095
+ type: 'error',
10096
+ inputs: [{ type: 'address', name: 'account' }],
10097
+ },
10029
10098
  { name: 'ChannelAlreadyExists', type: 'error', inputs: [] },
10030
10099
  { name: 'ChannelNotFound', type: 'error', inputs: [] },
10031
10100
  { name: 'NotPayer', type: 'error', inputs: [] },
package/tempo/Account.ts CHANGED
@@ -24,7 +24,7 @@ import { keccak256 } from '../utils/hash/keccak256.js'
24
24
  import { hashMessage } from '../utils/signature/hashMessage.js'
25
25
  import { hashTypedData } from '../utils/signature/hashTypedData.js'
26
26
  import type { SerializeTransactionFn } from '../utils/transaction/serializeTransaction.js'
27
- import { nativeMultisigFactory } from './Addresses.js'
27
+ import { configurableAccountRecoveryFactory } from './Addresses.js'
28
28
  import { parseApproval } from './accounts/Signature.js'
29
29
  import type { KeyAuthorizationManager } from './KeyAuthorizationManager.js'
30
30
  import * as Transaction from './Transaction.js'
@@ -281,8 +281,10 @@ export declare namespace fromSecp256k1 {
281
281
  *
282
282
  * The returned account does not hold a key itself. Omit `address` or set it to
283
283
  * `infer` to derive an account address from its initial config. For a current
284
- * config, set `address` to the stable account address. Pass the address directly
285
- * for an address-only account.
284
+ * config, set `address` to the stable account address. For an account
285
+ * upgraded in place with `Actions.accounts.upgrade`, set `address` to the
286
+ * upgraded account and pass the installed owners and threshold as `upgrade`.
287
+ * Pass the address directly for an address-only account.
286
288
  *
287
289
  * Owners can be accounts or addresses directly, or weighted `{ owner, weight }`
288
290
  * entries. Direct owners default to weight `1`, and `threshold` defaults to `1`.
@@ -309,7 +311,7 @@ export declare namespace fromSecp256k1 {
309
311
  * const transaction = await client.signTransaction(request)
310
312
  * ```
311
313
  *
312
- * @param value Initial config, current config, or account address.
314
+ * @param value Initial config, current config, upgrade config, or account address.
313
315
  * @returns Configurable account.
314
316
  */
315
317
  export function fromConfig(
@@ -318,6 +320,9 @@ export function fromConfig(
318
320
  export function fromConfig(
319
321
  value: fromConfig.CurrentConfig,
320
322
  ): ConfigurableAccount<AccountConfig.Config>
323
+ export function fromConfig(
324
+ value: fromConfig.UpgradeConfig,
325
+ ): ConfigurableAccount<AccountConfig.Config>
321
326
  export function fromConfig(
322
327
  address: Address.Address,
323
328
  ): ConfigurableAccount<undefined>
@@ -325,7 +330,12 @@ export function fromConfig(value: fromConfig.Parameters): ConfigurableAccount
325
330
  export function fromConfig(value: fromConfig.Parameters): ConfigurableAccount {
326
331
  const configInput = (() => {
327
332
  if (typeof value === 'string') return undefined
328
- const { address: _, ...config } = value
333
+ if ('upgrade' in value) return value.upgrade
334
+ const {
335
+ address: _,
336
+ factory: __,
337
+ ...config
338
+ } = value as fromConfig.InitialConfig
329
339
  return config
330
340
  })()
331
341
  const config = (() => {
@@ -335,16 +345,16 @@ export function fromConfig(value: fromConfig.Parameters): ConfigurableAccount {
335
345
  ? { owner: value, weight: 1 }
336
346
  : value,
337
347
  )
338
- return AccountConfig.from({
339
- ...configInput,
340
- owners: ownerEntries.map(({ owner, weight }) => ({
341
- owner: typeof owner === 'string' ? owner : owner.address,
342
- weight,
343
- })),
344
- threshold: configInput.threshold ?? 1,
345
- })
348
+ const owners = ownerEntries.map(({ owner, weight }) => ({
349
+ owner: typeof owner === 'string' ? owner : owner.address,
350
+ weight,
351
+ }))
352
+ const threshold = configInput.threshold ?? 1
353
+ if (typeof value !== 'string' && 'upgrade' in value)
354
+ return AccountConfig.fromUpgrade(value.address, { owners, threshold })
355
+ return AccountConfig.from({ ...configInput, owners, threshold })
346
356
  })()
347
- if (typeof value !== 'string') {
357
+ if (typeof value !== 'string' && !('upgrade' in value)) {
348
358
  if (
349
359
  (value.address === undefined || value.address === 'infer') &&
350
360
  config!.version !== 0n
@@ -362,7 +372,7 @@ export function fromConfig(value: fromConfig.Parameters): ConfigurableAccount {
362
372
  if (typeof value === 'string') return value
363
373
  if (value.address === undefined || value.address === 'infer')
364
374
  return AccountConfig.getAddress(config!, {
365
- factory: nativeMultisigFactory,
375
+ factory: value.factory ?? configurableAccountRecoveryFactory,
366
376
  })
367
377
  return value.address
368
378
  })(),
@@ -484,6 +494,11 @@ export declare namespace fromConfig {
484
494
  export type InitialConfig = {
485
495
  /** Derives the stable account address from this initial config. */
486
496
  address?: 'infer' | undefined
497
+ /**
498
+ * Recovery factory used to derive the address.
499
+ * @default `Addresses.configurableAccountRecoveryFactory`
500
+ */
501
+ factory?: Address.Address | undefined
487
502
  /** Weighted owners. */
488
503
  owners: readonly Owner[]
489
504
  /** Caller-chosen 32-byte salt. */
@@ -505,7 +520,24 @@ export declare namespace fromConfig {
505
520
  })
506
521
 
507
522
  /** Parameters for {@link fromConfig}. */
508
- export type Parameters = Address.Address | CurrentConfig | InitialConfig
523
+ export type Parameters =
524
+ | Address.Address
525
+ | CurrentConfig
526
+ | InitialConfig
527
+ | UpgradeConfig
528
+
529
+ /** Account upgraded in place and the owners and threshold it installed. */
530
+ export type UpgradeConfig = {
531
+ /** Upgraded account address. */
532
+ address: Address.Address
533
+ /** Owners and threshold installed by the upgrade. */
534
+ upgrade: {
535
+ /** Weighted owners. */
536
+ owners: readonly Owner[]
537
+ /** Minimum owner weight required for authorization. */
538
+ threshold?: number | undefined
539
+ }
540
+ }
509
541
  }
510
542
 
511
543
  export type ConfigurableAccount<
@@ -1110,6 +1142,10 @@ declare namespace fromAccessKey {
1110
1142
  export type ReturnValue = AccessKeyAccount
1111
1143
  }
1112
1144
 
1145
+ // TODO: support configurable accounts as access keys (TIP-1111): authorize a
1146
+ // configurable account with key type `configurable`, sign as it with a keychain
1147
+ // envelope wrapping its configurable signature, and accept those envelopes in the
1148
+ // relay fee payer.
1113
1149
  /** @internal */
1114
1150
  export function resolveAccessKey(
1115
1151
  accessKey: resolveAccessKey.Parameters,
@@ -12,13 +12,13 @@ export const accountImplementation =
12
12
  export const accountKeychain = '0xaAAAaaAA00000000000000000000000000000000'
13
13
  export const accountRegistrar = '0x7702ac0000000000000000000000000000000000'
14
14
  export const addressRegistry = '0xfdc0000000000000000000000000000000000000'
15
+ export const configurableAccount = '0xAACC000000000000000000000000000000000000'
16
+ /** Default configurable account recovery factory. Temporary until the production address is finalized. */
17
+ export const configurableAccountRecoveryFactory =
18
+ '0x7171717171717171717171717171717171717171'
15
19
  /** Current consensus committee precompile address, used with `Abis.currentCommittee` to read committee members. */
16
20
  export const currentCommittee = '0xC077e00000000000000000000000000000000000'
17
21
  export const feeManager = '0xfeec000000000000000000000000000000000000'
18
- export const nativeMultisig = '0xAACC000000000000000000000000000000000000'
19
- /** Temporary recovery factory until the production address is finalized. */
20
- export const nativeMultisigFactory =
21
- '0x7171717171717171717171717171717171717171'
22
22
  export const nonceManager = '0x4e4F4E4345000000000000000000000000000000'
23
23
  export const ousd = '0x20c0000000000000000000006a37DA5C996874BE'
24
24
  export const pathUsd = '0x20c0000000000000000000000000000000000000'
@@ -503,6 +503,34 @@ type DecoratorBase<
503
503
  ) => ReturnType<typeof accessKeyActions.watchWitnessBurned>
504
504
  }
505
505
  accounts: {
506
+ /**
507
+ * Derives a configurable account address from an initial config with the
508
+ * configurable account precompile.
509
+ *
510
+ * @example
511
+ * ```ts
512
+ * import { createClient, http } from 'viem'
513
+ * import { tempo } from 'viem/chains'
514
+ * import { Account, tempoActions } from 'viem/tempo'
515
+ *
516
+ * const client = createClient({
517
+ * account: Account.fromSecp256k1('0x...'),
518
+ * chain: tempo,
519
+ * transport: http(),
520
+ * }).extend(tempoActions())
521
+ *
522
+ * const address = await client.accounts.deriveAccount({
523
+ * owners: [{ owner: '0x...', weight: 1 }],
524
+ * threshold: 1,
525
+ * })
526
+ * ```
527
+ *
528
+ * @param parameters - Owners, threshold, and optional salt.
529
+ * @returns The configurable account address.
530
+ */
531
+ deriveAccount: (
532
+ parameters: accountsActions.deriveAccount.Parameters,
533
+ ) => Promise<accountsActions.deriveAccount.ReturnValue>
506
534
  /**
507
535
  * Gets the current cached config for a configurable account.
508
536
  *
@@ -543,6 +571,90 @@ type DecoratorBase<
543
571
  updateConfigSync: (
544
572
  parameters: accountsActions.updateConfigSync.Parameters<chain, account>,
545
573
  ) => Promise<accountsActions.updateConfigSync.ReturnValue>
574
+ /**
575
+ * Upgrades an existing account to a configurable account in place.
576
+ *
577
+ * @example
578
+ * ```ts
579
+ * import { createClient, http } from 'viem'
580
+ * import { tempo } from 'viem/chains'
581
+ * import { Account, tempoActions } from 'viem/tempo'
582
+ *
583
+ * const client = createClient({
584
+ * account: Account.fromSecp256k1('0x...'),
585
+ * chain: tempo,
586
+ * transport: http(),
587
+ * }).extend(tempoActions())
588
+ *
589
+ * const hash = await client.accounts.upgrade({
590
+ * owners: [{ owner: '0x...', weight: 1 }],
591
+ * threshold: 1,
592
+ * })
593
+ * ```
594
+ *
595
+ * @param parameters - Owners, threshold, and transaction parameters.
596
+ * @returns The transaction hash.
597
+ */
598
+ upgrade: (
599
+ parameters: accountsActions.upgrade.Parameters<chain, account>,
600
+ ) => Promise<accountsActions.upgrade.ReturnValue>
601
+ /**
602
+ * Upgrades an existing account to a configurable account in place and
603
+ * waits for confirmation.
604
+ *
605
+ * @example
606
+ * ```ts
607
+ * import { createClient, http } from 'viem'
608
+ * import { tempo } from 'viem/chains'
609
+ * import { Account, tempoActions } from 'viem/tempo'
610
+ *
611
+ * const client = createClient({
612
+ * account: Account.fromSecp256k1('0x...'),
613
+ * chain: tempo,
614
+ * transport: http(),
615
+ * }).extend(tempoActions())
616
+ *
617
+ * const { config } = await client.accounts.upgradeSync({
618
+ * owners: [{ owner: '0x...', weight: 1 }],
619
+ * threshold: 1,
620
+ * })
621
+ * ```
622
+ *
623
+ * @param parameters - Owners, threshold, and transaction parameters.
624
+ * @returns The installed configuration, its commitment, and the transaction receipt.
625
+ */
626
+ upgradeSync: (
627
+ parameters: accountsActions.upgradeSync.Parameters<chain, account>,
628
+ ) => Promise<accountsActions.upgradeSync.ReturnValue>
629
+ /**
630
+ * Verifies a configurable account signature against the account's
631
+ * current configuration.
632
+ *
633
+ * @example
634
+ * ```ts
635
+ * import { createClient, http } from 'viem'
636
+ * import { tempo } from 'viem/chains'
637
+ * import { Account, tempoActions } from 'viem/tempo'
638
+ *
639
+ * const client = createClient({
640
+ * account: Account.fromSecp256k1('0x...'),
641
+ * chain: tempo,
642
+ * transport: http(),
643
+ * }).extend(tempoActions())
644
+ *
645
+ * const valid = await client.accounts.verifyHash({
646
+ * account: '0x...',
647
+ * hash: '0x...',
648
+ * signature: '0x...',
649
+ * })
650
+ * ```
651
+ *
652
+ * @param parameters - Account, hash, and signature.
653
+ * @returns Whether the signature is valid for the account.
654
+ */
655
+ verifyHash: (
656
+ parameters: accountsActions.verifyHash.Parameters,
657
+ ) => Promise<accountsActions.verifyHash.ReturnValue>
546
658
  }
547
659
  amm: {
548
660
  /**
@@ -6206,11 +6318,15 @@ export function decorator() {
6206
6318
  'watchWitnessBurned',
6207
6319
  ]),
6208
6320
  accounts: bindActions(client, accountsActions, [
6321
+ 'deriveAccount',
6209
6322
  'getConfig',
6210
6323
  'getConfigCommitment',
6211
6324
  'getOperation',
6212
6325
  'updateConfig',
6213
6326
  'updateConfigSync',
6327
+ 'upgrade',
6328
+ 'upgradeSync',
6329
+ 'verifyHash',
6214
6330
  ]),
6215
6331
  amm: bindActions(client, ammActions, [
6216
6332
  'getPool',
@@ -34,6 +34,9 @@ export type Rpc =
34
34
  export const messages: Record<`${AbiErrorName}(${string})`, string> = {
35
35
  'AbdicationAlreadyScheduled(uint8)':
36
36
  'Abdication is already scheduled for capability {0}.',
37
+ 'AccountAlreadyConfigurable()':
38
+ 'The account is already a configurable account.',
39
+ 'AccountHasCode()': 'Accounts with code cannot be upgraded.',
37
40
  'AccountNotAllowed(address)': 'Account {0} is not allowed.',
38
41
  'ActiveLeaderRemoved()': 'The active leader cannot be removed.',
39
42
  'AddressAlreadyHasValidator()': 'This address already has a validator.',
@@ -100,6 +103,7 @@ export const messages: Record<`${AbiErrorName}(${string})`, string> = {
100
103
  'InvalidClaimAddress()': 'Invalid claim address.',
101
104
  'InvalidClosedLoopConfig()': 'Invalid closed-loop configuration.',
102
105
  'InvalidConfig()': 'Invalid configuration.',
106
+ 'InvalidConfigurableAccountOwner()': 'Invalid owner.',
103
107
  'InvalidCurrency()': 'Invalid currency.',
104
108
  'InvalidDepositTransition()': 'Invalid deposit transition.',
105
109
  'InvalidEncryptionKeyIndex(uint256)': 'Invalid encryption key index ({0}).',
@@ -114,7 +118,6 @@ export const messages: Record<`${AbiErrorName}(${string})`, string> = {
114
118
  'InvalidMasterAddress()': 'Invalid master address.',
115
119
  'InvalidMigrationIndex()': 'Invalid migration index.',
116
120
  'InvalidMode()': 'Invalid mode.',
117
- 'InvalidMultisigOwner()': 'Invalid owner.',
118
121
  'InvalidNonceKey()': 'Invalid nonce key.',
119
122
  'InvalidOwner()': 'Invalid owner.',
120
123
  'InvalidOwnerOrder()': 'Invalid owner order.',
@@ -191,11 +194,13 @@ export const messages: Record<`${AbiErrorName}(${string})`, string> = {
191
194
  'PolicyNotFound()': 'Policy not found.',
192
195
  'PolicyNotSimple()': 'Policy is not a simple policy.',
193
196
  'PortalIsPaused()': 'The portal is paused.',
197
+ 'PrimitiveRootRequired()': 'The root key must sign the upgrade transaction.',
194
198
  'ProofOfWorkFailed()': 'Proof of work failed.',
195
199
  'ProtectedAddress()': 'Address is protected.',
196
200
  'ProtocolNonceNotSupported()': 'Protocol nonce is not supported.',
197
201
  'PublicKeyAlreadyExists()': 'Public key already exists.',
198
202
  'ReentrantWithdrawal()': 'Reentrant withdrawals are not allowed.',
203
+ 'RootKeyRetired(address)': 'The root key of {0} is retired.',
199
204
  'SequencerConfigurationUnchanged()':
200
205
  'The sequencer configuration is unchanged.',
201
206
  'SignatureTypeMismatch(uint8,uint8)':
@@ -219,8 +224,11 @@ export const messages: Record<`${AbiErrorName}(${string})`, string> = {
219
224
  'Unauthorized()': 'Unauthorized.',
220
225
  'UnauthorizedCaller()': 'Unauthorized caller.',
221
226
  'UnauthorizedClaimer()': 'Unauthorized claimer.',
222
- 'UnauthorizedMultisigCaller()': 'Unauthorized multisig caller.',
227
+ 'UnauthorizedConfigurableAccountCaller()':
228
+ 'Unauthorized configurable account caller.',
223
229
  'Uninitialized()': 'Uninitialized.',
230
+ 'UpgradeMustBeOnlyCall()':
231
+ 'The upgrade must be the only call in the transaction.',
224
232
  'ValidatorAlreadyDeactivated()': 'Validator is already deactivated.',
225
233
  'ValidatorAlreadyExists()': 'Validator already exists.',
226
234
  'ValidatorNotFound()': 'Validator not found.',
@@ -310,6 +318,24 @@ export const hints: Partial<Record<keyof typeof messages, readonly string[]>> =
310
318
  'SupplyCapExceeded()': ['Mint a smaller amount, or raise the supply cap.'],
311
319
  'TickOutOfBounds(int16)': ['Use a tick within the allowed range.'],
312
320
  'Unauthorized()': ['The account lacks the permission this call requires.'],
321
+ 'AccountAlreadyConfigurable()': [
322
+ 'The account is already configurable. Rotate its owners with `updateConfig` instead.',
323
+ ],
324
+ 'AccountHasCode()': [
325
+ 'Only accounts without code or delegation can be upgraded in place.',
326
+ ],
327
+ 'PrimitiveRootRequired()': [
328
+ "Send the upgrade from the account's root key, not an access key or another account.",
329
+ ],
330
+ 'RootKeyRetired(address)': [
331
+ 'The account was upgraded to a configurable account. Sign with its owners instead of the retired root key.',
332
+ ],
333
+ 'UnauthorizedConfigurableAccountCaller()': [
334
+ 'Only the configurable account can update its own configuration.',
335
+ ],
336
+ 'UpgradeMustBeOnlyCall()': [
337
+ 'Send `upgradeAccount` as the only call, without a key authorization or authorization list.',
338
+ ],
313
339
  }
314
340
 
315
341
  /** Interpolate `{0}`, `{1}`, … placeholders with args. */
package/tempo/Hardfork.ts CHANGED
@@ -10,11 +10,25 @@ export const hardforks = [
10
10
  't4',
11
11
  't5',
12
12
  't6',
13
+ 't7',
14
+ 't8',
15
+ 't9',
16
+ 't10',
17
+ 't11',
18
+ 't12',
19
+ 't13',
20
+ 't14',
13
21
  ] as const
14
22
 
15
23
  export type Hardfork = (typeof hardforks)[number]
16
24
 
17
- /** Returns `true` if `current` is before `target`. */
25
+ /**
26
+ * Returns `true` if `current` is before `target`.
27
+ *
28
+ * Unknown `current` hardforks are treated as newer than every known hardfork.
29
+ */
18
30
  export function lt(current: string, target: Hardfork): boolean {
19
- return hardforks.indexOf(current as Hardfork) < hardforks.indexOf(target)
31
+ const index = hardforks.indexOf(current as Hardfork)
32
+ if (index === -1) return false
33
+ return index < hardforks.indexOf(target)
20
34
  }
@@ -49,11 +49,12 @@ export const addressRegistry = {
49
49
  resolveVirtualAddress: '0xe2fc56ef',
50
50
  } as const satisfies FunctionSelectors<typeof Abis.addressRegistry>
51
51
 
52
- export const nativeMultisig = {
52
+ export const configurableAccount = {
53
53
  deriveAccount: '0xce8e071c',
54
54
  getConfigCommitment: '0x5bd93359',
55
55
  updateConfig: '0x64203645',
56
- } as const satisfies FunctionSelectors<typeof Abis.nativeMultisig>
56
+ upgradeAccount: '0x5f5fdc31',
57
+ } as const satisfies FunctionSelectors<typeof Abis.configurableAccount>
57
58
 
58
59
  export const currentCommittee = {
59
60
  getCommitteeMembers: '0xb2a275f9',
@@ -73,6 +74,7 @@ export const receivePolicyGuard = {
73
74
  export const signatureVerifier = {
74
75
  recover: '0x19045a25',
75
76
  verify: '0x1a86b550',
77
+ verifyConfigurableAccount: '0x8a4c1645',
76
78
  verifyKeychain: '0x6c0c731e',
77
79
  verifyKeychainAdmin: '0x5f6fc5b7',
78
80
  } as const satisfies FunctionSelectors<typeof Abis.signatureVerifier>
@@ -103,8 +103,8 @@ export type TransactionRequestRpc = OneOf<
103
103
  TransactionRequestTempo<Hex.Hex, Hex.Hex, '0x76'>,
104
104
  'accountSimulation'
105
105
  > & {
106
- /** Account simulation spec, named `multisigSimulation` by the node. */
107
- multisigSimulation?: AccountSimulation.Rpc | undefined
106
+ /** Account simulation spec, named `configurableAccountSimulation` by the node. */
107
+ configurableAccountSimulation?: AccountSimulation.Rpc | undefined
108
108
  })
109
109
  >
110
110
 
@@ -4,7 +4,7 @@ import type * as Hex from 'ox/Hex'
4
4
  import * as Json from 'ox/Json'
5
5
  import { AccountConfig } from 'ox/tempo'
6
6
  import { BaseError } from '../../errors/base.js'
7
- import { nativeMultisigFactory } from '../Addresses.js'
7
+ import { configurableAccountRecoveryFactory } from '../Addresses.js'
8
8
  import type * as Store from '../Store.js'
9
9
 
10
10
  /** A valid 48-owner config is much smaller; 64 KiB bounds hostile store parsing work. */
@@ -78,7 +78,9 @@ function assertKey(options: {
78
78
  if (config.version === 0n) {
79
79
  if (
80
80
  !Address.isEqual(
81
- AccountConfig.getAddress(config, { factory: nativeMultisigFactory }),
81
+ AccountConfig.getAddress(config, {
82
+ factory: configurableAccountRecoveryFactory,
83
+ }),
82
84
  address,
83
85
  )
84
86
  )
@@ -106,7 +108,7 @@ function deserialize(value: string): AccountConfig.Config {
106
108
  /** Returns the store key for an account and config commitment. */
107
109
  function key(options: { address: Address.Address; commitment: Hex.Hex }) {
108
110
  const { address, commitment } = options
109
- return `multisig:config:${address.toLowerCase()}:${commitment.toLowerCase()}`
111
+ return `configurableAccount:config:${address.toLowerCase()}:${commitment.toLowerCase()}`
110
112
  }
111
113
 
112
114
  /** Serializes an account config for storage. */
@@ -173,12 +173,12 @@ function assertHash(operation: AccountOperation.Operation) {
173
173
 
174
174
  /** Returns the store key for an operation hash. */
175
175
  function operationKey(hash: Hex.Hex) {
176
- return `multisig:operation:${hash.toLowerCase()}`
176
+ return `configurableAccount:operation:${hash.toLowerCase()}`
177
177
  }
178
178
 
179
179
  /** Returns the store key for a submission attempt. */
180
180
  function submissionKey(hash: Hex.Hex, submissionId: Hex.Hex) {
181
- return `multisig:submission:${hash.toLowerCase()}:${submissionId.toLowerCase()}`
181
+ return `configurableAccount:submission:${hash.toLowerCase()}:${submissionId.toLowerCase()}`
182
182
  }
183
183
 
184
184
  /** Thrown when a stored account operation is malformed or unsupported. */