viem 2.56.1 → 2.56.3

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 (254) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/_cjs/actions/wallet/sendTransaction.js +9 -1
  3. package/_cjs/actions/wallet/sendTransaction.js.map +1 -1
  4. package/_cjs/actions/wallet/sendTransactionSync.js +9 -1
  5. package/_cjs/actions/wallet/sendTransactionSync.js.map +1 -1
  6. package/_cjs/errors/version.js +1 -1
  7. package/_cjs/tempo/Abis.js +11 -23
  8. package/_cjs/tempo/Abis.js.map +1 -1
  9. package/_cjs/tempo/Account.js +66 -61
  10. package/_cjs/tempo/Account.js.map +1 -1
  11. package/_cjs/tempo/Client.js +10 -2
  12. package/_cjs/tempo/Client.js.map +1 -1
  13. package/_cjs/tempo/Decorator.js +2 -1
  14. package/_cjs/tempo/Decorator.js.map +1 -1
  15. package/_cjs/tempo/Formatters.js +29 -9
  16. package/_cjs/tempo/Formatters.js.map +1 -1
  17. package/_cjs/tempo/Multisig.js +1093 -0
  18. package/_cjs/tempo/Multisig.js.map +1 -0
  19. package/_cjs/tempo/Selectors.js +2 -3
  20. package/_cjs/tempo/Selectors.js.map +1 -1
  21. package/_cjs/tempo/{Storage.js → Store.js} +34 -9
  22. package/_cjs/tempo/Store.js.map +1 -0
  23. package/_cjs/tempo/Transaction.js +15 -30
  24. package/_cjs/tempo/Transaction.js.map +1 -1
  25. package/_cjs/tempo/Transport.js +51 -5
  26. package/_cjs/tempo/Transport.js.map +1 -1
  27. package/_cjs/tempo/Zone.js.map +1 -1
  28. package/_cjs/tempo/actions/accessKey.js +102 -8
  29. package/_cjs/tempo/actions/accessKey.js.map +1 -1
  30. package/_cjs/tempo/actions/amm.js +6 -0
  31. package/_cjs/tempo/actions/amm.js.map +1 -1
  32. package/_cjs/tempo/actions/channel.js +12 -0
  33. package/_cjs/tempo/actions/channel.js.map +1 -1
  34. package/_cjs/tempo/actions/dex.js +10 -0
  35. package/_cjs/tempo/actions/dex.js.map +1 -1
  36. package/_cjs/tempo/actions/earn/deployment.js +13 -1
  37. package/_cjs/tempo/actions/earn/deployment.js.map +1 -1
  38. package/_cjs/tempo/actions/earn.js +17 -0
  39. package/_cjs/tempo/actions/earn.js.map +1 -1
  40. package/_cjs/tempo/actions/fee.js +4 -0
  41. package/_cjs/tempo/actions/fee.js.map +1 -1
  42. package/_cjs/tempo/actions/multisig.js +86 -28
  43. package/_cjs/tempo/actions/multisig.js.map +1 -1
  44. package/_cjs/tempo/actions/policy.js +8 -0
  45. package/_cjs/tempo/actions/policy.js.map +1 -1
  46. package/_cjs/tempo/actions/receivePolicy.js +6 -0
  47. package/_cjs/tempo/actions/receivePolicy.js.map +1 -1
  48. package/_cjs/tempo/actions/reward.js +4 -0
  49. package/_cjs/tempo/actions/reward.js.map +1 -1
  50. package/_cjs/tempo/actions/token.js +32 -0
  51. package/_cjs/tempo/actions/token.js.map +1 -1
  52. package/_cjs/tempo/actions/virtualAddress.js +2 -0
  53. package/_cjs/tempo/actions/virtualAddress.js.map +1 -1
  54. package/_cjs/tempo/actions/zone.js +7 -5
  55. package/_cjs/tempo/actions/zone.js.map +1 -1
  56. package/_cjs/tempo/chainConfig.js +180 -69
  57. package/_cjs/tempo/chainConfig.js.map +1 -1
  58. package/_cjs/tempo/index.js +5 -2
  59. package/_cjs/tempo/index.js.map +1 -1
  60. package/_cjs/tempo/internal/utils.js +2 -1
  61. package/_cjs/tempo/internal/utils.js.map +1 -1
  62. package/_cjs/tempo/multisig/Config.js +80 -0
  63. package/_cjs/tempo/multisig/Config.js.map +1 -0
  64. package/_cjs/tempo/multisig/Operation.js +163 -0
  65. package/_cjs/tempo/multisig/Operation.js.map +1 -0
  66. package/_cjs/utils/encoding/fromHex.js +1 -1
  67. package/_cjs/utils/encoding/fromHex.js.map +1 -1
  68. package/_cjs/utils/hash/isHash.js +1 -2
  69. package/_cjs/utils/hash/isHash.js.map +1 -1
  70. package/_esm/actions/wallet/sendTransaction.js +9 -1
  71. package/_esm/actions/wallet/sendTransaction.js.map +1 -1
  72. package/_esm/actions/wallet/sendTransactionSync.js +9 -1
  73. package/_esm/actions/wallet/sendTransactionSync.js.map +1 -1
  74. package/_esm/errors/version.js +1 -1
  75. package/_esm/tempo/Abis.js +11 -23
  76. package/_esm/tempo/Abis.js.map +1 -1
  77. package/_esm/tempo/Account.js +66 -61
  78. package/_esm/tempo/Account.js.map +1 -1
  79. package/_esm/tempo/Client.js +22 -3
  80. package/_esm/tempo/Client.js.map +1 -1
  81. package/_esm/tempo/Decorator.js +2 -1
  82. package/_esm/tempo/Decorator.js.map +1 -1
  83. package/_esm/tempo/Formatters.js +32 -11
  84. package/_esm/tempo/Formatters.js.map +1 -1
  85. package/_esm/tempo/Multisig.js +1126 -0
  86. package/_esm/tempo/Multisig.js.map +1 -0
  87. package/_esm/tempo/Selectors.js +2 -3
  88. package/_esm/tempo/Selectors.js.map +1 -1
  89. package/_esm/tempo/{Storage.js → Store.js} +37 -26
  90. package/_esm/tempo/Store.js.map +1 -0
  91. package/_esm/tempo/Transaction.js +16 -31
  92. package/_esm/tempo/Transaction.js.map +1 -1
  93. package/_esm/tempo/Transport.js +71 -6
  94. package/_esm/tempo/Transport.js.map +1 -1
  95. package/_esm/tempo/Zone.js +1 -2
  96. package/_esm/tempo/Zone.js.map +1 -1
  97. package/_esm/tempo/actions/accessKey.js +104 -20
  98. package/_esm/tempo/actions/accessKey.js.map +1 -1
  99. package/_esm/tempo/actions/amm.js +6 -0
  100. package/_esm/tempo/actions/amm.js.map +1 -1
  101. package/_esm/tempo/actions/channel.js +12 -0
  102. package/_esm/tempo/actions/channel.js.map +1 -1
  103. package/_esm/tempo/actions/dex.js +10 -0
  104. package/_esm/tempo/actions/dex.js.map +1 -1
  105. package/_esm/tempo/actions/earn/deployment.js +13 -1
  106. package/_esm/tempo/actions/earn/deployment.js.map +1 -1
  107. package/_esm/tempo/actions/earn.js +17 -0
  108. package/_esm/tempo/actions/earn.js.map +1 -1
  109. package/_esm/tempo/actions/fee.js +4 -0
  110. package/_esm/tempo/actions/fee.js.map +1 -1
  111. package/_esm/tempo/actions/multisig.js +129 -63
  112. package/_esm/tempo/actions/multisig.js.map +1 -1
  113. package/_esm/tempo/actions/policy.js +8 -0
  114. package/_esm/tempo/actions/policy.js.map +1 -1
  115. package/_esm/tempo/actions/receivePolicy.js +6 -0
  116. package/_esm/tempo/actions/receivePolicy.js.map +1 -1
  117. package/_esm/tempo/actions/reward.js +4 -0
  118. package/_esm/tempo/actions/reward.js.map +1 -1
  119. package/_esm/tempo/actions/token.js +32 -0
  120. package/_esm/tempo/actions/token.js.map +1 -1
  121. package/_esm/tempo/actions/virtualAddress.js +2 -0
  122. package/_esm/tempo/actions/virtualAddress.js.map +1 -1
  123. package/_esm/tempo/actions/zone.js +8 -6
  124. package/_esm/tempo/actions/zone.js.map +1 -1
  125. package/_esm/tempo/chainConfig.js +188 -86
  126. package/_esm/tempo/chainConfig.js.map +1 -1
  127. package/_esm/tempo/index.js +5 -3
  128. package/_esm/tempo/index.js.map +1 -1
  129. package/_esm/tempo/internal/utils.js +2 -1
  130. package/_esm/tempo/internal/utils.js.map +1 -1
  131. package/_esm/tempo/multisig/Config.js +84 -0
  132. package/_esm/tempo/multisig/Config.js.map +1 -0
  133. package/_esm/tempo/multisig/Operation.js +170 -0
  134. package/_esm/tempo/multisig/Operation.js.map +1 -0
  135. package/_esm/utils/encoding/fromHex.js +1 -1
  136. package/_esm/utils/encoding/fromHex.js.map +1 -1
  137. package/_esm/utils/hash/isHash.js +1 -2
  138. package/_esm/utils/hash/isHash.js.map +1 -1
  139. package/_types/actions/wallet/sendTransaction.d.ts.map +1 -1
  140. package/_types/actions/wallet/sendTransactionSync.d.ts.map +1 -1
  141. package/_types/chains/definitions/tempo.d.ts +72 -92
  142. package/_types/chains/definitions/tempo.d.ts.map +1 -1
  143. package/_types/chains/definitions/tempoDevnet.d.ts +72 -92
  144. package/_types/chains/definitions/tempoDevnet.d.ts.map +1 -1
  145. package/_types/chains/definitions/tempoLocalnet.d.ts +72 -92
  146. package/_types/chains/definitions/tempoLocalnet.d.ts.map +1 -1
  147. package/_types/chains/definitions/tempoModerato.d.ts +72 -92
  148. package/_types/chains/definitions/tempoModerato.d.ts.map +1 -1
  149. package/_types/errors/version.d.ts +1 -1
  150. package/_types/tempo/Abis.d.ts +54 -108
  151. package/_types/tempo/Abis.d.ts.map +1 -1
  152. package/_types/tempo/Account.d.ts +47 -20
  153. package/_types/tempo/Account.d.ts.map +1 -1
  154. package/_types/tempo/Client.d.ts +23 -1
  155. package/_types/tempo/Client.d.ts.map +1 -1
  156. package/_types/tempo/Decorator.d.ts +30 -5
  157. package/_types/tempo/Decorator.d.ts.map +1 -1
  158. package/_types/tempo/Formatters.d.ts.map +1 -1
  159. package/_types/tempo/Multisig.d.ts +37 -0
  160. package/_types/tempo/Multisig.d.ts.map +1 -0
  161. package/_types/tempo/Selectors.d.ts +2 -3
  162. package/_types/tempo/Selectors.d.ts.map +1 -1
  163. package/_types/tempo/Store.d.ts +62 -0
  164. package/_types/tempo/Store.d.ts.map +1 -0
  165. package/_types/tempo/Transaction.d.ts +12 -31
  166. package/_types/tempo/Transaction.d.ts.map +1 -1
  167. package/_types/tempo/Transport.d.ts +37 -5
  168. package/_types/tempo/Transport.d.ts.map +1 -1
  169. package/_types/tempo/Zone.d.ts +35 -6799
  170. package/_types/tempo/Zone.d.ts.map +1 -1
  171. package/_types/tempo/actions/accessKey.d.ts +38 -8
  172. package/_types/tempo/actions/accessKey.d.ts.map +1 -1
  173. package/_types/tempo/actions/amm.d.ts.map +1 -1
  174. package/_types/tempo/actions/channel.d.ts.map +1 -1
  175. package/_types/tempo/actions/dex.d.ts.map +1 -1
  176. package/_types/tempo/actions/earn/deployment.d.ts +3 -3
  177. package/_types/tempo/actions/earn/deployment.d.ts.map +1 -1
  178. package/_types/tempo/actions/earn.d.ts.map +1 -1
  179. package/_types/tempo/actions/fee.d.ts.map +1 -1
  180. package/_types/tempo/actions/multisig.d.ts +139 -136
  181. package/_types/tempo/actions/multisig.d.ts.map +1 -1
  182. package/_types/tempo/actions/policy.d.ts.map +1 -1
  183. package/_types/tempo/actions/receivePolicy.d.ts.map +1 -1
  184. package/_types/tempo/actions/reward.d.ts.map +1 -1
  185. package/_types/tempo/actions/token.d.ts.map +1 -1
  186. package/_types/tempo/actions/virtualAddress.d.ts.map +1 -1
  187. package/_types/tempo/actions/zone.d.ts +4 -4
  188. package/_types/tempo/actions/zone.d.ts.map +1 -1
  189. package/_types/tempo/chainConfig.d.ts +38 -48
  190. package/_types/tempo/chainConfig.d.ts.map +1 -1
  191. package/_types/tempo/index.d.ts +5 -5
  192. package/_types/tempo/index.d.ts.map +1 -1
  193. package/_types/tempo/internal/types.d.ts +1 -1
  194. package/_types/tempo/internal/types.d.ts.map +1 -1
  195. package/_types/tempo/internal/utils.d.ts +1 -0
  196. package/_types/tempo/internal/utils.d.ts.map +1 -1
  197. package/_types/tempo/multisig/Config.d.ts +42 -0
  198. package/_types/tempo/multisig/Config.d.ts.map +1 -0
  199. package/_types/tempo/multisig/Operation.d.ts +32 -0
  200. package/_types/tempo/multisig/Operation.d.ts.map +1 -0
  201. package/_types/types/chain.d.ts +10 -0
  202. package/_types/types/chain.d.ts.map +1 -1
  203. package/_types/utils/hash/isHash.d.ts +1 -2
  204. package/_types/utils/hash/isHash.d.ts.map +1 -1
  205. package/actions/wallet/sendTransaction.ts +9 -1
  206. package/actions/wallet/sendTransactionSync.ts +9 -1
  207. package/errors/version.ts +1 -1
  208. package/package.json +2 -2
  209. package/tempo/Abis.ts +11 -23
  210. package/tempo/Account.ts +136 -105
  211. package/tempo/Client.ts +46 -3
  212. package/tempo/Decorator.ts +40 -8
  213. package/tempo/Formatters.ts +39 -21
  214. package/tempo/Multisig.ts +1490 -0
  215. package/tempo/Selectors.ts +2 -3
  216. package/tempo/Store.ts +170 -0
  217. package/tempo/Transaction.ts +39 -64
  218. package/tempo/Transport.ts +125 -10
  219. package/tempo/Zone.ts +30 -4
  220. package/tempo/actions/accessKey.ts +210 -23
  221. package/tempo/actions/amm.ts +7 -0
  222. package/tempo/actions/channel.ts +12 -0
  223. package/tempo/actions/dex.ts +10 -0
  224. package/tempo/actions/earn/deployment.ts +16 -3
  225. package/tempo/actions/earn.ts +19 -0
  226. package/tempo/actions/fee.ts +4 -0
  227. package/tempo/actions/multisig.ts +192 -94
  228. package/tempo/actions/policy.ts +8 -0
  229. package/tempo/actions/receivePolicy.ts +6 -0
  230. package/tempo/actions/reward.ts +5 -0
  231. package/tempo/actions/token.ts +33 -0
  232. package/tempo/actions/virtualAddress.ts +2 -0
  233. package/tempo/actions/zone.ts +10 -8
  234. package/tempo/chainConfig.ts +259 -100
  235. package/tempo/index.ts +5 -4
  236. package/tempo/internal/types.ts +3 -2
  237. package/tempo/internal/utils.ts +2 -0
  238. package/tempo/multisig/Config.ts +131 -0
  239. package/tempo/multisig/Operation.ts +211 -0
  240. package/types/chain.ts +14 -0
  241. package/utils/encoding/fromHex.ts +1 -1
  242. package/utils/hash/isHash.ts +2 -3
  243. package/_cjs/tempo/Storage.js.map +0 -1
  244. package/_cjs/tempo/internal/multisig.js +0 -56
  245. package/_cjs/tempo/internal/multisig.js.map +0 -1
  246. package/_esm/tempo/Storage.js.map +0 -1
  247. package/_esm/tempo/internal/multisig.js +0 -56
  248. package/_esm/tempo/internal/multisig.js.map +0 -1
  249. package/_types/tempo/Storage.d.ts +0 -42
  250. package/_types/tempo/Storage.d.ts.map +0 -1
  251. package/_types/tempo/internal/multisig.d.ts +0 -13
  252. package/_types/tempo/internal/multisig.d.ts.map +0 -1
  253. package/tempo/Storage.ts +0 -115
  254. package/tempo/internal/multisig.ts +0 -72
package/tempo/Abis.ts CHANGED
@@ -464,21 +464,22 @@ export const nativeMultisig = [
464
464
  outputs: [{ type: 'address', name: 'account' }],
465
465
  },
466
466
  {
467
- name: 'isMultisigAccount',
467
+ name: 'getConfigCommitment',
468
468
  type: 'function',
469
469
  stateMutability: 'view',
470
470
  inputs: [{ type: 'address', name: 'account' }],
471
- outputs: [{ type: 'bool' }],
471
+ outputs: [{ type: 'bytes32', name: 'commitment' }],
472
472
  },
473
473
  {
474
- name: 'getConfig',
474
+ name: 'updateConfig',
475
475
  type: 'function',
476
- stateMutability: 'view',
477
- inputs: [{ type: 'address', name: 'account' }],
478
- outputs: [
476
+ stateMutability: 'nonpayable',
477
+ inputs: [
479
478
  {
480
479
  type: 'tuple',
480
+ name: 'current',
481
481
  components: [
482
+ { type: 'bytes32', name: 'salt' },
482
483
  { type: 'uint64', name: 'version' },
483
484
  { type: 'uint8', name: 'threshold' },
484
485
  {
@@ -491,13 +492,6 @@ export const nativeMultisig = [
491
492
  },
492
493
  ],
493
494
  },
494
- ],
495
- },
496
- {
497
- name: 'updateConfig',
498
- type: 'function',
499
- stateMutability: 'nonpayable',
500
- inputs: [
501
495
  { type: 'uint8', name: 'threshold' },
502
496
  {
503
497
  type: 'tuple[]',
@@ -510,16 +504,13 @@ export const nativeMultisig = [
510
504
  ],
511
505
  outputs: [],
512
506
  },
513
- {
514
- name: 'MultisigInitialized',
515
- type: 'event',
516
- inputs: [{ type: 'address', name: 'account', indexed: true }],
517
- },
518
507
  {
519
508
  name: 'MultisigConfigUpdated',
520
509
  type: 'event',
521
510
  inputs: [
522
511
  { type: 'address', name: 'account', indexed: true },
512
+ { type: 'bytes32', name: 'salt' },
513
+ { type: 'uint64', name: 'version' },
523
514
  { type: 'uint8', name: 'threshold' },
524
515
  {
525
516
  type: 'tuple[]',
@@ -531,18 +522,15 @@ export const nativeMultisig = [
531
522
  },
532
523
  ],
533
524
  },
534
- { name: 'NotMultisigAccount', type: 'error', inputs: [] },
535
525
  { name: 'InvalidAccount', type: 'error', inputs: [] },
536
526
  { name: 'InvalidConfig', type: 'error', inputs: [] },
537
527
  { name: 'InvalidThreshold', type: 'error', inputs: [] },
538
- { name: 'InvalidOwner', type: 'error', inputs: [] },
528
+ { name: 'InvalidMultisigOwner', type: 'error', inputs: [] },
539
529
  { name: 'InvalidWeight', type: 'error', inputs: [] },
540
530
  { name: 'TooManyOwners', type: 'error', inputs: [] },
541
531
  { name: 'DuplicateOwner', type: 'error', inputs: [] },
542
532
  { name: 'InvalidOwnerOrder', type: 'error', inputs: [] },
543
- { name: 'AccountAlreadyInitialized', type: 'error', inputs: [] },
544
- { name: 'UnauthorizedCaller', type: 'error', inputs: [] },
545
- { name: 'SameTransactionUpdateNotAllowed', type: 'error', inputs: [] },
533
+ { name: 'UnauthorizedMultisigCaller', type: 'error', inputs: [] },
546
534
  ] as const
547
535
 
548
536
  export const currentCommittee = [
package/tempo/Account.ts CHANGED
@@ -277,26 +277,28 @@ export declare namespace fromSecp256k1 {
277
277
  /**
278
278
  * Instantiates an Account for a native multisig (TIP-1061) config.
279
279
  *
280
- * The returned account does not hold a key itself. Pass an initial config to
281
- * derive and bootstrap an account, or pass the address of an initialized
282
- * account to reconstruct it without retaining the initial config.
280
+ * The returned account does not hold a key itself. Omit `address` or set it to
281
+ * `infer` to derive an account address from its initial config. For a current
282
+ * config, set `address` to the stable account address. Pass the address directly
283
+ * for an address-only account.
283
284
  *
284
285
  * Owners can be accounts or addresses directly, or weighted `{ owner, weight }`
285
286
  * entries. Direct owners default to weight `1`, and `threshold` defaults to `1`.
286
287
  * Local owner accounts are retained for signing, including nested multisigs.
287
- * Address-only configs keep the external approval flow, where owner approvals
288
- * are collected separately and provided via `signatures`.
288
+ * Configs containing only owner addresses require external approvals through
289
+ * `signatures`.
289
290
  *
290
- * Accepts a raw config and normalizes it internally (via `MultisigConfig.from`),
291
- * so callers don't need to call `MultisigConfig.from` themselves.
291
+ * Normalizes supplied config fields with `MultisigConfig.from`, so callers do
292
+ * not need to normalize owner ordering themselves.
292
293
  *
293
294
  * @example
294
295
  * ```ts
295
296
  * import { Account } from 'viem/tempo'
296
297
  *
297
298
  * const account = Account.fromMultisig({
298
- * threshold: 2,
299
+ * address: 'infer',
299
300
  * owners: [owner_1, owner_2],
301
+ * threshold: 2,
300
302
  * })
301
303
  *
302
304
  * // The multisig config is inferred from the account.
@@ -305,46 +307,70 @@ export declare namespace fromSecp256k1 {
305
307
  * const transaction = await client.signTransaction(request)
306
308
  * ```
307
309
  *
308
- * @param value Initial multisig config or initialized multisig address.
310
+ * @param value Initial config, current config, or multisig address.
309
311
  * @returns Multisig account.
310
312
  */
311
313
  export function fromMultisig(
312
- config: fromMultisig.Config,
314
+ value: fromMultisig.InitialConfig,
315
+ ): MultisigAccount<MultisigConfig.Config>
316
+ export function fromMultisig(
317
+ value: fromMultisig.CurrentConfig,
313
318
  ): MultisigAccount<MultisigConfig.Config>
314
319
  export function fromMultisig(
315
320
  address: Address.Address,
316
321
  ): MultisigAccount<undefined>
317
322
  export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount
318
323
  export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
319
- const config = (() => {
324
+ const configInput = (() => {
320
325
  if (typeof value === 'string') return undefined
321
- const ownerEntries = value.owners.map((value) =>
326
+ const { address: _, ...config } = value
327
+ return config
328
+ })()
329
+ const config = (() => {
330
+ if (!configInput) return undefined
331
+ const ownerEntries = configInput.owners.map((value) =>
322
332
  typeof value === 'string' || 'address' in value
323
333
  ? { owner: value, weight: 1 }
324
334
  : value,
325
335
  )
326
336
  return MultisigConfig.from({
327
- ...value,
337
+ ...configInput,
328
338
  owners: ownerEntries.map(({ owner, weight }) => ({
329
339
  owner: typeof owner === 'string' ? owner : owner.address,
330
340
  weight,
331
341
  })),
332
- threshold: value.threshold ?? 1,
342
+ threshold: configInput.threshold ?? 1,
333
343
  })
334
344
  })()
345
+ if (typeof value !== 'string') {
346
+ if (
347
+ (value.address === undefined || value.address === 'infer') &&
348
+ config!.version !== 0n
349
+ )
350
+ throw new Error('An initial multisig config must have version zero.')
351
+ if (
352
+ value.address !== undefined &&
353
+ value.address !== 'infer' &&
354
+ config!.version === 0n
355
+ )
356
+ throw new Error('A current multisig config must have a version.')
357
+ }
335
358
  const address = Address.checksum(
336
- typeof value === 'string' ? value : MultisigConfig.getAddress(config!),
359
+ (() => {
360
+ if (typeof value === 'string') return value
361
+ if (value.address === undefined || value.address === 'infer')
362
+ return MultisigConfig.getAddress(config!)
363
+ return value.address
364
+ })(),
337
365
  )
338
- const ownerAccounts =
339
- typeof value === 'string'
340
- ? []
341
- : value.owners.flatMap((value) => {
342
- const owner =
343
- typeof value === 'string' || 'address' in value
344
- ? value
345
- : value.owner
346
- return typeof owner === 'string' ? [] : [parseAccount(owner)]
347
- })
366
+ const ownerAccounts = (() => {
367
+ if (!configInput) return []
368
+ return configInput.owners.flatMap((value) => {
369
+ const owner =
370
+ typeof value === 'string' || 'address' in value ? value : value.owner
371
+ return typeof owner === 'string' ? [] : [parseAccount(owner)]
372
+ })
373
+ })()
348
374
  const owners =
349
375
  config?.owners.flatMap(({ owner }) => {
350
376
  const account = ownerAccounts.find((account) =>
@@ -360,8 +386,10 @@ export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
360
386
  publicKey: '0x',
361
387
  source: 'multisig',
362
388
  type: 'local',
363
- async sign() {
364
- throw new Error('`sign` is not supported for multisig accounts.')
389
+ async sign({ hash }) {
390
+ return SignatureEnvelope.serialize(
391
+ await signMultisig(account, { payload: hash }),
392
+ )
365
393
  },
366
394
  async signMessage() {
367
395
  throw new Error('`signMessage` is not supported for multisig accounts.')
@@ -369,6 +397,19 @@ export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
369
397
  async signTransaction(transaction, options) {
370
398
  const { serializer = Transaction.serialize } = options ?? {}
371
399
  const request = transaction as Transaction.TransactionSerializableTempo
400
+ if (request.owner) {
401
+ const owner = parseAccount(request.owner)
402
+ if (owner.type !== 'local')
403
+ throw new Error(
404
+ 'A local owner account is required to approve a multisig transaction.',
405
+ )
406
+ if (owner.source !== 'root' && owner.source !== 'multisig')
407
+ throw new Error(
408
+ 'A Tempo owner account is required to approve a multisig transaction.',
409
+ )
410
+ const { owner: _, ...ownerRequest } = request
411
+ return await owner.signTransaction(ownerRequest as never, options)
412
+ }
372
413
  if (owners.length === 0)
373
414
  return (await serializer(transaction as never)) as Hex.Hex
374
415
 
@@ -380,51 +421,31 @@ export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
380
421
  : { feePayerSignature: null }),
381
422
  }
382
423
  const payload = keccak256(await serializer(presign as never))
383
- const requestMultisig = request.multisig
384
- const requestAccount = requestMultisig
385
- ? typeof requestMultisig === 'string'
386
- ? requestMultisig
387
- : MultisigConfig.getAddress(requestMultisig)
388
- : address
424
+ const simulation = request.multisigSimulation
425
+ const requestAccount = simulation?.account ?? address
389
426
 
390
427
  if (!Address.isEqual(requestAccount, address)) {
391
- const state = request.multisigOwnerStates?.find((state) =>
392
- Address.isEqual(state.account, address),
393
- )
394
- if (state && !state.initialized)
395
- throw new Error('Nested multisig owners must be initialized.')
428
+ if (!simulation)
429
+ throw new Error('A multisig config is required for local signing.')
430
+ const parentConfig = MultisigConfig.from(simulation.config)
396
431
  const parentDigest = MultisigConfig.getSignPayload({
397
- ...(typeof requestMultisig === 'string'
398
- ? { account: requestMultisig }
399
- : { initialConfig: requestMultisig! }),
432
+ account: requestAccount,
433
+ config: parentConfig,
400
434
  payload,
401
- version: request.multisigVersion,
402
435
  })
403
436
  return SignatureEnvelope.serialize(
404
437
  await signMultisig(account, {
405
438
  payload: parentDigest,
406
- states: request.multisigOwnerStates,
407
- version: state?.version,
408
439
  }),
409
440
  )
410
441
  }
411
442
 
412
- const keyAuthorizationSignature = request.keyAuthorization?.signature
413
- const keyAuthorizationInitializes =
414
- keyAuthorizationSignature?.type === 'multisig' &&
415
- typeof keyAuthorizationSignature.init !== 'undefined'
416
443
  const signature = await signMultisig(account, {
417
- init:
418
- typeof config !== 'undefined' &&
419
- !request.nonce &&
420
- !request.nonceKey &&
421
- !keyAuthorizationInitializes,
444
+ config: simulation?.config,
422
445
  payload,
423
446
  signatures: request.signatures?.map((signature) =>
424
447
  SignatureEnvelope.from(signature),
425
448
  ),
426
- states: request.multisigOwnerStates,
427
- version: request.multisigVersion,
428
449
  })
429
450
  return (await serializer(
430
451
  transaction as never,
@@ -439,6 +460,38 @@ export function fromMultisig(value: fromMultisig.Parameters): MultisigAccount {
439
460
  }
440
461
 
441
462
  export declare namespace fromMultisig {
463
+ /** Initial version-zero multisig config. */
464
+ export type Config = InitialConfig
465
+
466
+ /** Stable multisig account address and its current config. */
467
+ export type CurrentConfig = {
468
+ /** Stable multisig account address. */
469
+ address: Address.Address
470
+ /** Weighted owners. */
471
+ owners: readonly Owner[]
472
+ /** Caller-chosen 32-byte salt. */
473
+ salt: MultisigConfig.Config['salt']
474
+ /** Minimum total owner weight required for authorization. */
475
+ threshold: MultisigConfig.Config['threshold']
476
+ /** Current configuration version. */
477
+ version: MultisigConfig.Config<bigint | number>['version']
478
+ }
479
+
480
+ /** Initial version-zero multisig config. */
481
+ export type InitialConfig = {
482
+ /** Derives the stable account address from this initial config. */
483
+ address?: 'infer' | undefined
484
+ /** Weighted owners. */
485
+ owners: readonly Owner[]
486
+ /** Caller-chosen 32-byte salt. */
487
+ salt?: MultisigConfig.Input['salt'] | undefined
488
+ /** Minimum owner weight required for authorization. */
489
+ threshold?: number | undefined
490
+ /** Initial configuration version. */
491
+ version?: 0 | 0n | undefined
492
+ }
493
+
494
+ /** Multisig owner account or address, optionally with an explicit weight. */
442
495
  export type Owner =
443
496
  | Address.Address
444
497
  | LocalAccount
@@ -446,20 +499,16 @@ export declare namespace fromMultisig {
446
499
  owner: Address.Address | LocalAccount
447
500
  })
448
501
 
449
- export type Config = Omit<MultisigConfig.Config, 'owners' | 'threshold'> & {
450
- owners: readonly Owner[]
451
- threshold?: number | undefined
452
- }
453
-
454
- export type Parameters = Address.Address | Config
502
+ /** Parameters for {@link fromMultisig}. */
503
+ export type Parameters = Address.Address | CurrentConfig | InitialConfig
455
504
  }
456
505
 
457
506
  export type MultisigAccount<
458
507
  config extends MultisigConfig.Config | undefined =
459
508
  | MultisigConfig.Config
460
509
  | undefined,
461
- > = LocalAccount<'multisig'> & {
462
- /** Normalized initial config, or `undefined` when instantiated from an address. */
510
+ > = RequiredBy<LocalAccount<'multisig'>, 'sign'> & {
511
+ /** Normalized config, or `undefined` for an address-only account. */
463
512
  config: config
464
513
  /** @internal Local owner accounts available for signing. */
465
514
  owners: readonly LocalAccount[]
@@ -472,30 +521,19 @@ function isMultisigAccount(account: LocalAccount): account is MultisigAccount {
472
521
  async function signMultisig(
473
522
  account: MultisigAccount,
474
523
  parameters: {
475
- init?: boolean | undefined
524
+ config?: MultisigConfig.Config | undefined
476
525
  payload: Hex.Hex
477
526
  signatures?: readonly SignatureEnvelope.SignatureEnvelope[] | undefined
478
- states?: readonly Transaction.MultisigOwnerState[] | undefined
479
- version?: bigint | undefined
480
527
  },
481
528
  ): Promise<SignatureEnvelope.Multisig> {
482
- const {
483
- init = false,
484
- payload,
485
- signatures: providedSignatures = [],
486
- states = [],
487
- version = 0n,
488
- } = parameters
489
- const state = states.find((state) =>
490
- Address.isEqual(state.account, account.address),
491
- )
492
- const currentConfig = state?.config ?? account.config
529
+ const { config, payload, signatures: providedSignatures = [] } = parameters
530
+ const currentConfig = config ?? account.config
493
531
  if (!currentConfig)
494
- throw new Error('Current multisig config is required for local signing.')
532
+ throw new Error('A current multisig config is required for local signing.')
495
533
  const digest = MultisigConfig.getSignPayload({
496
534
  account: account.address,
535
+ config: currentConfig,
497
536
  payload,
498
- version,
499
537
  })
500
538
  const signatures = [...providedSignatures]
501
539
  const signedOwners = new Set<Address.Address>()
@@ -514,7 +552,12 @@ async function signMultisig(
514
552
  weight += Number(owner.weight)
515
553
  }
516
554
 
517
- for (const owner of currentConfig.owners) {
555
+ const owners = [...currentConfig.owners].sort(
556
+ (a, b) =>
557
+ Number(b.weight) - Number(a.weight) ||
558
+ a.owner.toLowerCase().localeCompare(b.owner.toLowerCase()),
559
+ )
560
+ for (const owner of owners) {
518
561
  const address = owner.owner.toLowerCase() as Address.Address
519
562
  if (signedOwners.has(address)) continue
520
563
  const ownerAccount = account.owners.find((account) =>
@@ -523,16 +566,9 @@ async function signMultisig(
523
566
  if (!ownerAccount) continue
524
567
 
525
568
  if (isMultisigAccount(ownerAccount)) {
526
- const state = states.find((state) =>
527
- Address.isEqual(state.account, ownerAccount.address),
528
- )
529
- if (state && !state.initialized)
530
- throw new Error('Nested multisig owners must be initialized.')
531
569
  signatures.push(
532
570
  await signMultisig(ownerAccount, {
533
571
  payload: digest,
534
- states,
535
- version: state?.version,
536
572
  }),
537
573
  )
538
574
  } else {
@@ -551,16 +587,14 @@ async function signMultisig(
551
587
  if (weight < Number(currentConfig.threshold))
552
588
  throw new Error('Local multisig owners do not meet the threshold.')
553
589
 
554
- if (init && !account.config)
555
- throw new Error('Initial multisig config is required for bootstrap.')
556
590
  return SignatureEnvelope.from({
557
591
  account: account.address,
558
- ...(init ? { init: account.config } : {}),
592
+ config: currentConfig,
559
593
  signatures: SignatureEnvelope.sortMultisigApprovals({
560
594
  account: account.address,
595
+ config: currentConfig,
561
596
  payload,
562
597
  signatures,
563
- version,
564
598
  }),
565
599
  }) as SignatureEnvelope.Multisig
566
600
  }
@@ -820,13 +854,11 @@ export async function signKeyAuthorization(
820
854
  )
821
855
  return SignatureEnvelope.serialize(
822
856
  await signMultisig(account, {
823
- init: multisigState.init,
857
+ config: multisigState.config,
824
858
  payload: hash,
825
859
  signatures: signatures?.map((signature) =>
826
860
  SignatureEnvelope.from(signature),
827
861
  ),
828
- states: multisigState.states,
829
- version: multisigState.version,
830
862
  }),
831
863
  )
832
864
  }
@@ -861,9 +893,7 @@ export declare namespace signKeyAuthorization {
861
893
  /** @internal Current state used when a multisig account signs the authorization. */
862
894
  multisig?:
863
895
  | {
864
- init: boolean
865
- states?: readonly Transaction.MultisigOwnerState[] | undefined
866
- version: bigint
896
+ config: MultisigConfig.Config
867
897
  }
868
898
  | undefined
869
899
  /** Serialized approvals from external multisig owners. */
@@ -952,17 +982,18 @@ function fromBase(parameters: fromBase.Parameters): Account_base {
952
982
  // primitive signature over the multisig owner approval digest, instead of
953
983
  // a full serialized transaction. Approvals are combined later in
954
984
  // `sendTransaction({ signatures })`.
955
- const { multisig, multisigVersion } = transaction as {
956
- multisig?: Address.Address | MultisigConfig.Config | undefined
957
- multisigVersion?: bigint | undefined
985
+ const { multisigSimulation } = transaction as {
986
+ multisigSimulation?: {
987
+ account: Address.Address
988
+ config: MultisigConfig.Config
989
+ }
958
990
  }
959
- if (multisig) {
991
+ if (multisigSimulation) {
992
+ const config = MultisigConfig.from(multisigSimulation.config)
960
993
  const digest = MultisigConfig.getSignPayload({
961
- ...(typeof multisig === 'string'
962
- ? { account: multisig }
963
- : { initialConfig: multisig }),
994
+ account: multisigSimulation.account,
995
+ config,
964
996
  payload,
965
- version: multisigVersion,
966
997
  })
967
998
  return await sign({ hash: digest, raw: true })
968
999
  }
package/tempo/Client.ts CHANGED
@@ -25,6 +25,8 @@ import type { RpcSchema } from '../types/eip1193.js'
25
25
  import type { Prettify } from '../types/utils.js'
26
26
  import { tempo, tempoTestnet } from './Chain.js'
27
27
  import { type Decorator, decorator as tempoActions } from './Decorator.js'
28
+ import * as Store from './Store.js'
29
+ import { withMultisig } from './Transport.js'
28
30
 
29
31
  /**
30
32
  * Configuration for a Tempo {@link Client}.
@@ -52,6 +54,19 @@ export type ClientConfig<
52
54
  * @default tempo (or `tempoTestnet` when `testnet` is truthy)
53
55
  */
54
56
  chain?: chain | Chain | undefined
57
+ /**
58
+ * Enables native multisig approval coordination. Pass `true` to use an
59
+ * in-memory store or provide a shared store.
60
+ *
61
+ * @default undefined
62
+ */
63
+ experimental_multisig?:
64
+ | true
65
+ | {
66
+ /** Store shared by multisig coordinators. */
67
+ store: Store.Atomic
68
+ }
69
+ | undefined
55
70
  /**
56
71
  * Default fee token for the Client. Extended onto the chain so it applies
57
72
  * to every transaction sent with the Client.
@@ -106,7 +121,8 @@ export type CreateClientErrorType = ErrorType
106
121
  * Defaults to the `tempo` mainnet chain and `http` transport, so a minimal
107
122
  * client can be created with `createClient()`. Pass `testnet` to use the
108
123
  * Tempo testnet, or `chain` to override the chain entirely. Pass `feeToken`
109
- * to set a default fee token for every transaction.
124
+ * to set a default fee token for every transaction. Pass
125
+ * `experimental_multisig` to coordinate multisig owner approvals.
110
126
  *
111
127
  * @example
112
128
  * ```ts
@@ -138,6 +154,16 @@ export type CreateClientErrorType = ErrorType
138
154
  * })
139
155
  * ```
140
156
  *
157
+ * @example
158
+ * ```ts
159
+ * import { createClient } from 'viem/tempo'
160
+ *
161
+ * // Multisig coordination with a client-local in-memory store.
162
+ * const client = createClient({
163
+ * experimental_multisig: true,
164
+ * })
165
+ * ```
166
+ *
141
167
  * @param parameters - Parameters.
142
168
  * @returns The Tempo Client.
143
169
  */
@@ -156,7 +182,15 @@ export function createClient<
156
182
  : accountOrAddress,
157
183
  rpcSchema
158
184
  > {
159
- const { chain, feeToken, testnet, tokens, transport, ...rest } = parameters
185
+ const {
186
+ chain,
187
+ experimental_multisig,
188
+ feeToken,
189
+ testnet,
190
+ tokens,
191
+ transport,
192
+ ...rest
193
+ } = parameters
160
194
  const baseChain = chain ?? (testnet ? tempoTestnet : tempo)
161
195
  const resolvedChain =
162
196
  feeToken && typeof (baseChain as { extend?: unknown }).extend === 'function'
@@ -164,11 +198,20 @@ export function createClient<
164
198
  feeToken,
165
199
  })
166
200
  : baseChain
201
+ const transport_ = transport ?? http()
202
+ const resolvedTransport = experimental_multisig
203
+ ? withMultisig(
204
+ transport_,
205
+ experimental_multisig === true
206
+ ? { store: Store.memory() }
207
+ : experimental_multisig,
208
+ )
209
+ : transport_
167
210
  return createClient_({
168
211
  ...rest,
169
212
  chain: resolvedChain,
170
213
  tokens: tokens ?? tokenSets.tempo,
171
- transport: transport ?? http(),
214
+ transport: resolvedTransport,
172
215
  } as ClientConfig_)
173
216
  .extend(publicActions)
174
217
  .extend(walletActions)
@@ -306,6 +306,33 @@ type DecoratorBase<
306
306
  revokeSync: (
307
307
  parameters: accessKeyActions.revokeSync.Parameters<chain, account>,
308
308
  ) => Promise<accessKeyActions.revokeSync.ReturnValue>
309
+ /**
310
+ * Signs a key authorization or adds one coordinated multisig approval.
311
+ *
312
+ * @example
313
+ * ```ts
314
+ * const pending = await client.accessKey.signAuthorization({
315
+ * accessKey,
316
+ * account: multisig,
317
+ * owner: owner_1,
318
+ * })
319
+ * const success = await client.accessKey.signAuthorization({
320
+ * hash: pending.hash,
321
+ * owner: owner_2,
322
+ * })
323
+ * ```
324
+ *
325
+ * @param parameters - Authorization fields, or a stored operation hash.
326
+ * @returns A signed key authorization with multisig operation metadata when coordinated.
327
+ */
328
+ signAuthorization: {
329
+ (
330
+ parameters: accessKeyActions.signAuthorization.CoordinatedParameters,
331
+ ): Promise<accessKeyActions.signAuthorization.CoordinatedReturnValue>
332
+ (
333
+ parameters: accessKeyActions.signAuthorization.LocalParameters<account>,
334
+ ): Promise<accessKeyActions.signAuthorization.ReturnValue>
335
+ }
309
336
  /**
310
337
  * Updates the spending limit for a specific token on an authorized access key.
311
338
  *
@@ -2366,23 +2393,27 @@ type DecoratorBase<
2366
2393
  }
2367
2394
  multisig: {
2368
2395
  /**
2369
- * Gets the current configuration for an initialized multisig account.
2396
+ * Gets the current cached config for a multisig account.
2370
2397
  *
2371
2398
  * @param parameters - Parameters.
2372
- * @returns The current version, threshold, and owners.
2399
+ * @returns The config, or `null` when it is unknown.
2373
2400
  */
2374
2401
  getConfig: (
2375
2402
  parameters: multisigActions.getConfig.Parameters,
2376
2403
  ) => Promise<multisigActions.getConfig.ReturnValue>
2404
+ /** Gets the current configuration commitment for a multisig account. */
2405
+ getConfigCommitment: (
2406
+ parameters: multisigActions.getConfigCommitment.Parameters,
2407
+ ) => Promise<multisigActions.getConfigCommitment.ReturnValue>
2377
2408
  /**
2378
- * Checks whether an address is an initialized native multisig account.
2409
+ * Gets a coordinated multisig operation by its hash.
2379
2410
  *
2380
2411
  * @param parameters - Parameters.
2381
- * @returns Whether the account is initialized.
2412
+ * @returns The operation, or `null` when it is unknown.
2382
2413
  */
2383
- isInitialized: (
2384
- parameters: multisigActions.isInitialized.Parameters,
2385
- ) => Promise<multisigActions.isInitialized.ReturnValue>
2414
+ getOperation: (
2415
+ parameters: multisigActions.getOperation.Parameters,
2416
+ ) => Promise<multisigActions.getOperation.ReturnValue>
2386
2417
  /**
2387
2418
  * Replaces the current configuration for a native multisig account.
2388
2419
  *
@@ -6008,7 +6039,8 @@ export function decorator() {
6008
6039
  faucet: bindActions(client, faucetActions, ['fund', 'fundSync']),
6009
6040
  multisig: bindActions(client, multisigActions, [
6010
6041
  'getConfig',
6011
- 'isInitialized',
6042
+ 'getConfigCommitment',
6043
+ 'getOperation',
6012
6044
  'updateConfig',
6013
6045
  'updateConfigSync',
6014
6046
  ]),