@openzeppelin/miden-multisig-client 0.17.0-rc.2 → 0.17.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 (278) hide show
  1. package/README.md +172 -47
  2. package/dist/account/builder.d.ts +2 -2
  3. package/dist/account/builder.d.ts.map +1 -1
  4. package/dist/account/builder.js +49 -24
  5. package/dist/account/builder.js.map +1 -1
  6. package/dist/connectivity.d.ts +2 -0
  7. package/dist/connectivity.d.ts.map +1 -1
  8. package/dist/connectivity.js +7 -4
  9. package/dist/connectivity.js.map +1 -1
  10. package/dist/index.d.ts +8 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +7 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/multisig/authArgErrors.d.ts +59 -0
  15. package/dist/multisig/authArgErrors.d.ts.map +1 -0
  16. package/dist/multisig/authArgErrors.js +115 -0
  17. package/dist/multisig/authArgErrors.js.map +1 -0
  18. package/dist/multisig/helpers.d.ts +5 -0
  19. package/dist/multisig/helpers.d.ts.map +1 -1
  20. package/dist/multisig/helpers.js +7 -2
  21. package/dist/multisig/helpers.js.map +1 -1
  22. package/dist/multisig.d.ts +140 -0
  23. package/dist/multisig.d.ts.map +1 -1
  24. package/dist/multisig.js +419 -12
  25. package/dist/multisig.js.map +1 -1
  26. package/dist/procedures.d.ts +1 -1
  27. package/dist/procedures.js +1 -1
  28. package/dist/recovery/proposalNoteImport.d.ts +173 -0
  29. package/dist/recovery/proposalNoteImport.d.ts.map +1 -0
  30. package/dist/recovery/proposalNoteImport.js +411 -0
  31. package/dist/recovery/proposalNoteImport.js.map +1 -0
  32. package/dist/recovery/publicNoteBackfill.d.ts +168 -0
  33. package/dist/recovery/publicNoteBackfill.d.ts.map +1 -0
  34. package/dist/recovery/publicNoteBackfill.js +368 -0
  35. package/dist/recovery/publicNoteBackfill.js.map +1 -0
  36. package/dist/recovery/recoverNotes.d.ts +147 -0
  37. package/dist/recovery/recoverNotes.d.ts.map +1 -0
  38. package/dist/recovery/recoverNotes.js +163 -0
  39. package/dist/recovery/recoverNotes.js.map +1 -0
  40. package/dist/recovery/transportDrain.d.ts +124 -0
  41. package/dist/recovery/transportDrain.d.ts.map +1 -0
  42. package/dist/recovery/transportDrain.js +262 -0
  43. package/dist/recovery/transportDrain.js.map +1 -0
  44. package/dist/transaction/consumeNotes.d.ts.map +1 -1
  45. package/dist/transaction/consumeNotes.js +4 -1
  46. package/dist/transaction/consumeNotes.js.map +1 -1
  47. package/dist/transaction/p2id.d.ts.map +1 -1
  48. package/dist/transaction/p2id.js +4 -1
  49. package/dist/transaction/p2id.js.map +1 -1
  50. package/dist/transaction/summary.d.ts +10 -4
  51. package/dist/transaction/summary.d.ts.map +1 -1
  52. package/dist/transaction/summary.js +13 -7
  53. package/dist/transaction/summary.js.map +1 -1
  54. package/dist/transaction/updateGuardian.js +4 -1
  55. package/dist/transaction/updateGuardian.js.map +1 -1
  56. package/dist/transaction/updateProcedureThreshold.js +4 -1
  57. package/dist/transaction/updateProcedureThreshold.js.map +1 -1
  58. package/dist/transaction/updateSigners.js +4 -1
  59. package/dist/transaction/updateSigners.js.map +1 -1
  60. package/dist/transaction.d.ts +1 -1
  61. package/dist/transaction.d.ts.map +1 -1
  62. package/dist/transaction.js +1 -1
  63. package/dist/transaction.js.map +1 -1
  64. package/package.json +14 -10
  65. package/src/account/builder.ts +87 -35
  66. package/src/connectivity.ts +9 -4
  67. package/src/index.ts +34 -1
  68. package/src/multisig/authArgErrors.ts +138 -0
  69. package/src/multisig/helpers.ts +7 -2
  70. package/src/multisig.ts +513 -20
  71. package/src/procedures.ts +1 -1
  72. package/src/recovery/proposalNoteImport.ts +548 -0
  73. package/src/recovery/publicNoteBackfill.ts +502 -0
  74. package/src/recovery/recoverNotes.ts +288 -0
  75. package/src/recovery/transportDrain.ts +330 -0
  76. package/src/transaction/consumeNotes.ts +4 -1
  77. package/src/transaction/p2id.ts +4 -1
  78. package/src/transaction/summary.ts +13 -7
  79. package/src/transaction/updateGuardian.ts +4 -1
  80. package/src/transaction/updateProcedureThreshold.ts +4 -1
  81. package/src/transaction/updateSigners.ts +4 -1
  82. package/src/transaction.ts +1 -1
  83. package/dist/account/builder.test.d.ts +0 -2
  84. package/dist/account/builder.test.d.ts.map +0 -1
  85. package/dist/account/builder.test.js +0 -166
  86. package/dist/account/builder.test.js.map +0 -1
  87. package/dist/account/masm/account-components/auth.d.ts +0 -2
  88. package/dist/account/masm/account-components/auth.d.ts.map +0 -1
  89. package/dist/account/masm/account-components/auth.js +0 -46
  90. package/dist/account/masm/account-components/auth.js.map +0 -1
  91. package/dist/account/masm/index.d.ts +0 -2
  92. package/dist/account/masm/index.d.ts.map +0 -1
  93. package/dist/account/masm/index.js +0 -4
  94. package/dist/account/masm/index.js.map +0 -1
  95. package/dist/account/masm.d.ts +0 -2
  96. package/dist/account/masm.d.ts.map +0 -1
  97. package/dist/account/masm.js +0 -4
  98. package/dist/account/masm.js.map +0 -1
  99. package/dist/account/storage.test.d.ts +0 -2
  100. package/dist/account/storage.test.d.ts.map +0 -1
  101. package/dist/account/storage.test.js +0 -73
  102. package/dist/account/storage.test.js.map +0 -1
  103. package/dist/client.test.d.ts +0 -2
  104. package/dist/client.test.d.ts.map +0 -1
  105. package/dist/client.test.js +0 -380
  106. package/dist/client.test.js.map +0 -1
  107. package/dist/connectivity.test.d.ts +0 -2
  108. package/dist/connectivity.test.d.ts.map +0 -1
  109. package/dist/connectivity.test.js +0 -61
  110. package/dist/connectivity.test.js.map +0 -1
  111. package/dist/inspector.test.d.ts +0 -2
  112. package/dist/inspector.test.d.ts.map +0 -1
  113. package/dist/inspector.test.js +0 -425
  114. package/dist/inspector.test.js.map +0 -1
  115. package/dist/lookupAuth.test.d.ts +0 -2
  116. package/dist/lookupAuth.test.d.ts.map +0 -1
  117. package/dist/lookupAuth.test.js +0 -138
  118. package/dist/lookupAuth.test.js.map +0 -1
  119. package/dist/multisig/consumeNotesErrors.test.d.ts +0 -2
  120. package/dist/multisig/consumeNotesErrors.test.d.ts.map +0 -1
  121. package/dist/multisig/consumeNotesErrors.test.js +0 -28
  122. package/dist/multisig/consumeNotesErrors.test.js.map +0 -1
  123. package/dist/multisig/helpers.test.d.ts +0 -2
  124. package/dist/multisig/helpers.test.d.ts.map +0 -1
  125. package/dist/multisig/helpers.test.js +0 -94
  126. package/dist/multisig/helpers.test.js.map +0 -1
  127. package/dist/multisig.test.d.ts +0 -2
  128. package/dist/multisig.test.d.ts.map +0 -1
  129. package/dist/multisig.test.js +0 -4112
  130. package/dist/multisig.test.js.map +0 -1
  131. package/dist/proposal/factory.test.d.ts +0 -2
  132. package/dist/proposal/factory.test.d.ts.map +0 -1
  133. package/dist/proposal/factory.test.js +0 -32
  134. package/dist/proposal/factory.test.js.map +0 -1
  135. package/dist/proposal/metadata.test.d.ts +0 -2
  136. package/dist/proposal/metadata.test.d.ts.map +0 -1
  137. package/dist/proposal/metadata.test.js +0 -193
  138. package/dist/proposal/metadata.test.js.map +0 -1
  139. package/dist/prover/config.test.d.ts +0 -2
  140. package/dist/prover/config.test.d.ts.map +0 -1
  141. package/dist/prover/config.test.js +0 -54
  142. package/dist/prover/config.test.js.map +0 -1
  143. package/dist/prover/errors.test.d.ts +0 -2
  144. package/dist/prover/errors.test.d.ts.map +0 -1
  145. package/dist/prover/errors.test.js +0 -29
  146. package/dist/prover/errors.test.js.map +0 -1
  147. package/dist/prover/retry.test.d.ts +0 -2
  148. package/dist/prover/retry.test.d.ts.map +0 -1
  149. package/dist/prover/retry.test.js +0 -20
  150. package/dist/prover/retry.test.js.map +0 -1
  151. package/dist/prover/workflow.test.d.ts +0 -2
  152. package/dist/prover/workflow.test.d.ts.map +0 -1
  153. package/dist/prover/workflow.test.js +0 -105
  154. package/dist/prover/workflow.test.js.map +0 -1
  155. package/dist/raw-client.test.d.ts +0 -2
  156. package/dist/raw-client.test.d.ts.map +0 -1
  157. package/dist/raw-client.test.js +0 -111
  158. package/dist/raw-client.test.js.map +0 -1
  159. package/dist/rpc/config.test.d.ts +0 -2
  160. package/dist/rpc/config.test.d.ts.map +0 -1
  161. package/dist/rpc/config.test.js +0 -24
  162. package/dist/rpc/config.test.js.map +0 -1
  163. package/dist/rpc/errors.test.d.ts +0 -2
  164. package/dist/rpc/errors.test.d.ts.map +0 -1
  165. package/dist/rpc/errors.test.js +0 -34
  166. package/dist/rpc/errors.test.js.map +0 -1
  167. package/dist/rpc/retry.test.d.ts +0 -2
  168. package/dist/rpc/retry.test.d.ts.map +0 -1
  169. package/dist/rpc/retry.test.js +0 -98
  170. package/dist/rpc/retry.test.js.map +0 -1
  171. package/dist/signers/ecdsa.test.d.ts +0 -2
  172. package/dist/signers/ecdsa.test.d.ts.map +0 -1
  173. package/dist/signers/ecdsa.test.js +0 -88
  174. package/dist/signers/ecdsa.test.js.map +0 -1
  175. package/dist/signers/falcon.test.d.ts +0 -2
  176. package/dist/signers/falcon.test.d.ts.map +0 -1
  177. package/dist/signers/falcon.test.js +0 -161
  178. package/dist/signers/falcon.test.js.map +0 -1
  179. package/dist/signers/miden-wallet.ecdsa-recovery.test.d.ts +0 -2
  180. package/dist/signers/miden-wallet.ecdsa-recovery.test.d.ts.map +0 -1
  181. package/dist/signers/miden-wallet.ecdsa-recovery.test.js +0 -148
  182. package/dist/signers/miden-wallet.ecdsa-recovery.test.js.map +0 -1
  183. package/dist/signers/miden-wallet.test.d.ts +0 -2
  184. package/dist/signers/miden-wallet.test.d.ts.map +0 -1
  185. package/dist/signers/miden-wallet.test.js +0 -164
  186. package/dist/signers/miden-wallet.test.js.map +0 -1
  187. package/dist/signers/para.test.d.ts +0 -2
  188. package/dist/signers/para.test.d.ts.map +0 -1
  189. package/dist/signers/para.test.js +0 -146
  190. package/dist/signers/para.test.js.map +0 -1
  191. package/dist/transaction/index.d.ts +0 -8
  192. package/dist/transaction/index.d.ts.map +0 -1
  193. package/dist/transaction/index.js +0 -7
  194. package/dist/transaction/index.js.map +0 -1
  195. package/dist/transaction/p2id.test.d.ts +0 -2
  196. package/dist/transaction/p2id.test.d.ts.map +0 -1
  197. package/dist/transaction/p2id.test.js +0 -246
  198. package/dist/transaction/p2id.test.js.map +0 -1
  199. package/dist/transaction/rpoRandomCoin.test.d.ts +0 -2
  200. package/dist/transaction/rpoRandomCoin.test.d.ts.map +0 -1
  201. package/dist/transaction/rpoRandomCoin.test.js +0 -52
  202. package/dist/transaction/rpoRandomCoin.test.js.map +0 -1
  203. package/dist/transaction/summary.test.d.ts +0 -2
  204. package/dist/transaction/summary.test.d.ts.map +0 -1
  205. package/dist/transaction/summary.test.js +0 -26
  206. package/dist/transaction/summary.test.js.map +0 -1
  207. package/dist/transaction.test.d.ts +0 -2
  208. package/dist/transaction.test.d.ts.map +0 -1
  209. package/dist/transaction.test.js +0 -122
  210. package/dist/transaction.test.js.map +0 -1
  211. package/dist/types/proposal.test.d.ts +0 -2
  212. package/dist/types/proposal.test.d.ts.map +0 -1
  213. package/dist/types/proposal.test.js +0 -56
  214. package/dist/types/proposal.test.js.map +0 -1
  215. package/dist/utils/digest.test.d.ts +0 -2
  216. package/dist/utils/digest.test.d.ts.map +0 -1
  217. package/dist/utils/digest.test.js +0 -48
  218. package/dist/utils/digest.test.js.map +0 -1
  219. package/dist/utils/ecdsa.test.d.ts +0 -2
  220. package/dist/utils/ecdsa.test.d.ts.map +0 -1
  221. package/dist/utils/ecdsa.test.js +0 -131
  222. package/dist/utils/ecdsa.test.js.map +0 -1
  223. package/dist/utils/encoding.test.d.ts +0 -2
  224. package/dist/utils/encoding.test.d.ts.map +0 -1
  225. package/dist/utils/encoding.test.js +0 -185
  226. package/dist/utils/encoding.test.js.map +0 -1
  227. package/dist/utils/key.test.d.ts +0 -2
  228. package/dist/utils/key.test.d.ts.map +0 -1
  229. package/dist/utils/key.test.js +0 -82
  230. package/dist/utils/key.test.js.map +0 -1
  231. package/dist/utils/signature.test.d.ts +0 -2
  232. package/dist/utils/signature.test.d.ts.map +0 -1
  233. package/dist/utils/signature.test.js +0 -164
  234. package/dist/utils/signature.test.js.map +0 -1
  235. package/dist/utils/word.test.d.ts +0 -2
  236. package/dist/utils/word.test.d.ts.map +0 -1
  237. package/dist/utils/word.test.js +0 -54
  238. package/dist/utils/word.test.js.map +0 -1
  239. package/masm/account_components/auth/guarded_multisig.masm +0 -42
  240. package/src/account/builder.test.ts +0 -238
  241. package/src/account/masm/account-components/auth.ts +0 -46
  242. package/src/account/masm/index.ts +0 -4
  243. package/src/account/masm.ts +0 -4
  244. package/src/account/storage.test.ts +0 -90
  245. package/src/client.test.ts +0 -473
  246. package/src/connectivity.test.ts +0 -67
  247. package/src/inspector.test.ts +0 -542
  248. package/src/lookupAuth.test.ts +0 -185
  249. package/src/multisig/consumeNotesErrors.test.ts +0 -43
  250. package/src/multisig/helpers.test.ts +0 -114
  251. package/src/multisig.test.ts +0 -5008
  252. package/src/proposal/factory.test.ts +0 -40
  253. package/src/proposal/metadata.test.ts +0 -235
  254. package/src/prover/config.test.ts +0 -90
  255. package/src/prover/errors.test.ts +0 -61
  256. package/src/prover/retry.test.ts +0 -38
  257. package/src/prover/workflow.test.ts +0 -145
  258. package/src/raw-client.test.ts +0 -171
  259. package/src/rpc/config.test.ts +0 -45
  260. package/src/rpc/errors.test.ts +0 -69
  261. package/src/rpc/retry.test.ts +0 -144
  262. package/src/signers/ecdsa.test.ts +0 -111
  263. package/src/signers/falcon.test.ts +0 -197
  264. package/src/signers/miden-wallet.ecdsa-recovery.test.ts +0 -201
  265. package/src/signers/miden-wallet.test.ts +0 -206
  266. package/src/signers/para.test.ts +0 -186
  267. package/src/transaction/index.ts +0 -13
  268. package/src/transaction/p2id.test.ts +0 -371
  269. package/src/transaction/rpoRandomCoin.test.ts +0 -64
  270. package/src/transaction/summary.test.ts +0 -32
  271. package/src/transaction.test.ts +0 -142
  272. package/src/types/proposal.test.ts +0 -68
  273. package/src/utils/digest.test.ts +0 -55
  274. package/src/utils/ecdsa.test.ts +0 -164
  275. package/src/utils/encoding.test.ts +0 -233
  276. package/src/utils/key.test.ts +0 -91
  277. package/src/utils/signature.test.ts +0 -210
  278. package/src/utils/word.test.ts +0 -64
@@ -1,542 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { AccountInspector, assertCompleteDetectedConfig } from './inspector.js';
3
- import type { DetectedMultisigConfig } from './inspector.js';
4
-
5
- // Mock the Miden SDK
6
- vi.mock('@miden-sdk/miden-sdk', () => {
7
- const createMockWord = (values: bigint[]) => ({
8
- toU64s: () => values,
9
- toHex: () => '0x' + values.map(v => v.toString(16).padStart(16, '0')).join(''),
10
- });
11
-
12
- // Faithful to the real SDK's read semantics (verified against the wasm
13
- // glue and miden-protocol): getItem returns undefined for an absent slot;
14
- // getMapItem returns undefined only when the slot is absent or not a map,
15
- // and the EMPTY word for a missing key in an existing map
16
- // (StorageMap::get is unwrap_or_default). Neither throws for "not found".
17
- const createMockStorage = (slots: Map<string, any>, maps: Map<string, Map<string, any>>) => ({
18
- getItem: (slotName: string) => slots.get(slotName),
19
- getMapItem: (slotName: string, key: any) => {
20
- const map = maps.get(slotName);
21
- if (!map) return undefined;
22
- const keyStr = key.toU64s?.()[0]?.toString() ?? '0';
23
- return map.get(keyStr) ?? createMockWord([0n, 0n, 0n, 0n]);
24
- },
25
- });
26
-
27
- const createMockVault = (assets: Array<{ faucetId: string; amount: bigint }>) => ({
28
- fungibleAssets: () => assets.map(a => ({
29
- faucetId: () => ({ toString: () => a.faucetId }),
30
- amount: () => a.amount,
31
- })),
32
- });
33
-
34
- return {
35
- Account: {
36
- deserialize: vi.fn((bytes: Uint8Array) => {
37
- // Return different mocked accounts based on test scenario
38
- // Default: 2-of-3 multisig with GUARDIAN enabled
39
- const slot0 = createMockWord([2n, 3n, 0n, 0n]); // threshold=2, numSigners=3
40
-
41
- const signerMap = new Map<string, any>();
42
- signerMap.set('0', createMockWord([BigInt('0x1111111111111111'), BigInt('0x2222222222222222'), BigInt('0x3333333333333333'), BigInt('0x4444444444444444')]));
43
- signerMap.set('1', createMockWord([BigInt('0x5555555555555555'), BigInt('0x6666666666666666'), BigInt('0x7777777777777777'), BigInt('0x8888888888888888')]));
44
- signerMap.set('2', createMockWord([BigInt('0xaaaaaaaaaaaaaaaa'), BigInt('0xbbbbbbbbbbbbbbbb'), BigInt('0xcccccccccccccccc'), BigInt('0xdddddddddddddddd')]));
45
-
46
- const guardianMap = new Map<string, any>();
47
- guardianMap.set('0', createMockWord([BigInt('0xeeeeeeeeeeeeeeee'), BigInt('0xffffffffffffffff'), BigInt('0x0000000000000001'), BigInt('0x0000000000000002')]));
48
-
49
- const slots = new Map<string, any>();
50
- slots.set('miden::standards::auth::multisig::threshold_config', slot0);
51
-
52
- const maps = new Map<string, Map<string, any>>();
53
- maps.set('miden::standards::auth::multisig::approver_public_keys', signerMap);
54
- maps.set('miden::standards::auth::guardian::pub_key', guardianMap);
55
-
56
- return {
57
- storage: () => createMockStorage(slots, maps),
58
- // The contract-version guard checks for the pinned auth procedure.
59
- code: () => ({ hasProcedure: () => true }),
60
- vault: () => createMockVault([
61
- { faucetId: '0xfaucet1', amount: 1000n },
62
- { faucetId: '0xfaucet2', amount: 500n },
63
- ]),
64
- };
65
- }),
66
- },
67
- Word: Object.assign(
68
- vi.fn().mockImplementation((arr: BigUint64Array) => ({
69
- toU64s: () => Array.from(arr),
70
- toHex: () => '0x' + Array.from(arr).map(v => v.toString(16).padStart(16, '0')).join(''),
71
- })),
72
- {
73
- fromHex: vi.fn((hex: string) => ({
74
- toU64s: () => [0n, 0n, 0n, 0n],
75
- toHex: () => hex,
76
- })),
77
- },
78
- ),
79
- };
80
- });
81
-
82
- describe('AccountInspector', () => {
83
- beforeEach(() => {
84
- vi.clearAllMocks();
85
- });
86
-
87
- describe('fromBase64', () => {
88
- it('deserializes account from base64 and extracts config', () => {
89
- const base64 = btoa(String.fromCharCode(...new Uint8Array([1, 2, 3])));
90
- const config = AccountInspector.fromBase64(base64);
91
-
92
- expect(config.threshold).toBe(2);
93
- expect(config.numSigners).toBe(3);
94
- });
95
-
96
- it('extracts the GUARDIAN commitment', () => {
97
- const base64 = btoa(String.fromCharCode(...new Uint8Array([1, 2, 3])));
98
- const config = AccountInspector.fromBase64(base64);
99
-
100
- expect(config.guardianCommitment).toMatch(/^0x[a-f0-9]+$/);
101
- });
102
-
103
- it('extracts signer commitments', () => {
104
- const base64 = btoa(String.fromCharCode(...new Uint8Array([1, 2, 3])));
105
- const config = AccountInspector.fromBase64(base64);
106
-
107
- expect(config.signerCommitments).toHaveLength(3);
108
- config.signerCommitments.forEach(commitment => {
109
- expect(commitment).toMatch(/^0x[a-f0-9]+$/);
110
- });
111
- });
112
-
113
- it('extracts vault balances', () => {
114
- const base64 = btoa(String.fromCharCode(...new Uint8Array([1, 2, 3])));
115
- const config = AccountInspector.fromBase64(base64);
116
-
117
- expect(config.vaultBalances).toHaveLength(2);
118
- expect(config.vaultBalances[0]).toEqual({ faucetId: '0xfaucet1', amount: 1000n });
119
- expect(config.vaultBalances[1]).toEqual({ faucetId: '0xfaucet2', amount: 500n });
120
- });
121
- });
122
-
123
- describe('fromAccount', () => {
124
- it('extracts threshold from slot 0', async () => {
125
- const { Account } = await import('@miden-sdk/miden-sdk');
126
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
127
- const config = AccountInspector.fromAccount(account);
128
-
129
- expect(config.threshold).toBe(2);
130
- });
131
-
132
- it('extracts numSigners from slot 0', async () => {
133
- const { Account } = await import('@miden-sdk/miden-sdk');
134
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
135
- const config = AccountInspector.fromAccount(account);
136
-
137
- expect(config.numSigners).toBe(3);
138
- });
139
-
140
- it('rejects accounts built from a different contract version', async () => {
141
- const { Account } = await import('@miden-sdk/miden-sdk');
142
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
143
- // Same account shape, but its code lacks the pinned auth procedure —
144
- // root-keyed reads against it would silently miss its stored overrides.
145
- const foreign = {
146
- ...account,
147
- code: () => ({ hasProcedure: () => false }),
148
- };
149
-
150
- expect(() => AccountInspector.fromAccount(foreign as never)).toThrow(
151
- /unsupported contract version/,
152
- );
153
- });
154
- });
155
- });
156
-
157
- describe('AccountInspector edge cases', () => {
158
- beforeEach(() => {
159
- vi.clearAllMocks();
160
- });
161
-
162
- it('returns a null GUARDIAN commitment when the guardian pub_key slot is absent', async () => {
163
- const { Account } = await import('@miden-sdk/miden-sdk');
164
-
165
- // Override mock for this test: no guardian pub_key entry present.
166
- vi.mocked(Account.deserialize).mockReturnValueOnce({
167
- code: () => ({ hasProcedure: () => true }),
168
- storage: () => ({
169
- getItem: (slotName: string) => {
170
- if (slotName === 'miden::standards::auth::multisig::threshold_config') return { toU64s: () => [1n, 1n, 0n, 0n] };
171
- return { toU64s: () => [0n, 0n, 0n, 0n] };
172
- },
173
- getMapItem: (slotName: string, key: any) => {
174
- if (slotName === 'miden::standards::auth::multisig::approver_public_keys' && key.toU64s?.()[0] === 0n) {
175
- return {
176
- toHex: () => '0x' + 'a'.repeat(64),
177
- toU64s: () => [1n, 2n, 3n, 4n],
178
- };
179
- }
180
- throw new Error('Not found');
181
- },
182
- }),
183
- vault: () => ({
184
- fungibleAssets: () => [],
185
- }),
186
- } as any);
187
-
188
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
189
- const config = AccountInspector.fromAccount(account);
190
-
191
- expect(config.guardianCommitment).toBeNull();
192
- });
193
-
194
- it('handles account with empty vault', async () => {
195
- const { Account } = await import('@miden-sdk/miden-sdk');
196
-
197
- vi.mocked(Account.deserialize).mockReturnValueOnce({
198
- code: () => ({ hasProcedure: () => true }),
199
- storage: () => ({
200
- getItem: () => ({ toU64s: () => [1n, 1n, 0n, 0n] }),
201
- getMapItem: () => {
202
- throw new Error('Not found');
203
- },
204
- }),
205
- vault: () => ({
206
- fungibleAssets: () => [],
207
- }),
208
- } as any);
209
-
210
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
211
- const config = AccountInspector.fromAccount(account);
212
-
213
- expect(config.vaultBalances).toEqual([]);
214
- });
215
-
216
- it('handles missing signer map entries gracefully', async () => {
217
- const { Account } = await import('@miden-sdk/miden-sdk');
218
-
219
- vi.mocked(Account.deserialize).mockReturnValueOnce({
220
- code: () => ({ hasProcedure: () => true }),
221
- storage: () => ({
222
- getItem: (slotName: string) => {
223
- if (slotName === 'miden::standards::auth::multisig::threshold_config') return { toU64s: () => [2n, 5n, 0n, 0n] }; // threshold=2, numSigners=5
224
- return { toU64s: () => [0n, 0n, 0n, 0n] };
225
- },
226
- getMapItem: () => {
227
- throw new Error('Map entry not found');
228
- },
229
- }),
230
- vault: () => ({
231
- fungibleAssets: () => [],
232
- }),
233
- } as any);
234
-
235
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
236
- const config = AccountInspector.fromAccount(account);
237
-
238
- // Should gracefully handle missing entries
239
- expect(config.numSigners).toBe(5);
240
- expect(config.signerCommitments).toEqual([]); // All entries missing
241
- });
242
-
243
- it('handles vault access error gracefully', async () => {
244
- const { Account } = await import('@miden-sdk/miden-sdk');
245
-
246
- vi.mocked(Account.deserialize).mockReturnValueOnce({
247
- code: () => ({ hasProcedure: () => true }),
248
- storage: () => ({
249
- getItem: () => ({ toU64s: () => [1n, 1n, 0n, 0n] }),
250
- getMapItem: () => {
251
- throw new Error('Not found');
252
- },
253
- }),
254
- vault: () => {
255
- throw new Error('Vault access failed');
256
- },
257
- } as any);
258
-
259
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
260
- const config = AccountInspector.fromAccount(account);
261
-
262
- expect(config.vaultBalances).toEqual([]);
263
- });
264
- });
265
-
266
- describe('AccountInspector.getSignerPublicKeyCommitments', () => {
267
- beforeEach(() => {
268
- vi.clearAllMocks();
269
- });
270
-
271
- it('returns all signer commitments ordered by signer index', async () => {
272
- const { Account } = await import('@miden-sdk/miden-sdk');
273
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
274
-
275
- const commitments = AccountInspector.getSignerPublicKeyCommitments(account);
276
-
277
- expect(commitments).toEqual([
278
- '0x1111111111111111222222222222222233333333333333334444444444444444',
279
- '0x5555555555555555666666666666666677777777777777778888888888888888',
280
- '0xaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccdddddddddddddddd',
281
- ]);
282
- });
283
-
284
- it('rejects accounts built from a different contract version', async () => {
285
- const { Account } = await import('@miden-sdk/miden-sdk');
286
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
287
- const foreign = {
288
- ...account,
289
- code: () => ({ hasProcedure: () => false }),
290
- };
291
-
292
- expect(() => AccountInspector.getSignerPublicKeyCommitments(foreign as never)).toThrow(
293
- /unsupported contract version/,
294
- );
295
- });
296
-
297
- it('throws when a signer map entry is the empty word instead of truncating', async () => {
298
- const { Account } = await import('@miden-sdk/miden-sdk');
299
-
300
- // Real SDK semantics: entries 0 and 1 exist, entries 2..4 come back as
301
- // the empty word (StorageMap::get is unwrap_or_default) — NOT undefined
302
- // and NOT a throw.
303
- const entries = new Map<string, any>([
304
- ['0', { toU64s: () => [1n, 2n, 3n, 4n], toHex: () => '0x' + 'a'.repeat(64) }],
305
- ['1', { toU64s: () => [5n, 6n, 7n, 8n], toHex: () => '0x' + 'b'.repeat(64) }],
306
- ]);
307
- vi.mocked(Account.deserialize).mockReturnValueOnce({
308
- code: () => ({ hasProcedure: () => true }),
309
- storage: () => ({
310
- getItem: (slotName: string) => {
311
- if (slotName === 'miden::standards::auth::multisig::threshold_config') return { toU64s: () => [2n, 5n, 0n, 0n] };
312
- return undefined;
313
- },
314
- getMapItem: (slotName: string, key: any) => {
315
- if (slotName !== 'miden::standards::auth::multisig::approver_public_keys') return undefined;
316
- const keyStr = key.toU64s?.()[0]?.toString() ?? '0';
317
- return entries.get(keyStr) ?? { toU64s: () => [0n, 0n, 0n, 0n] };
318
- },
319
- }),
320
- } as any);
321
-
322
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
323
-
324
- expect(() => AccountInspector.getSignerPublicKeyCommitments(account)).toThrow(
325
- /missing signer public key at index 2/
326
- );
327
- });
328
-
329
- it('throws when the signer map slot itself is absent', async () => {
330
- const { Account } = await import('@miden-sdk/miden-sdk');
331
-
332
- vi.mocked(Account.deserialize).mockReturnValueOnce({
333
- code: () => ({ hasProcedure: () => true }),
334
- storage: () => ({
335
- getItem: (slotName: string) => {
336
- if (slotName === 'miden::standards::auth::multisig::threshold_config') return { toU64s: () => [2n, 3n, 0n, 0n] };
337
- return undefined;
338
- },
339
- getMapItem: () => undefined,
340
- }),
341
- } as any);
342
-
343
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
344
-
345
- expect(() => AccountInspector.getSignerPublicKeyCommitments(account)).toThrow(
346
- /missing signer public key at index 0/
347
- );
348
- });
349
-
350
- it('throws when the threshold config slot is absent', async () => {
351
- const { Account } = await import('@miden-sdk/miden-sdk');
352
-
353
- vi.mocked(Account.deserialize).mockReturnValueOnce({
354
- code: () => ({ hasProcedure: () => true }),
355
- storage: () => ({
356
- getItem: () => undefined,
357
- getMapItem: () => undefined,
358
- }),
359
- } as any);
360
-
361
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
362
-
363
- expect(() => AccountInspector.getSignerPublicKeyCommitments(account)).toThrow(
364
- /not a guarded-multisig account/
365
- );
366
- });
367
-
368
- it('throws when the threshold config reports zero signers', async () => {
369
- const { Account } = await import('@miden-sdk/miden-sdk');
370
-
371
- vi.mocked(Account.deserialize).mockReturnValueOnce({
372
- code: () => ({ hasProcedure: () => true }),
373
- storage: () => ({
374
- getItem: () => ({ toU64s: () => [0n, 0n, 0n, 0n] }),
375
- getMapItem: () => undefined,
376
- }),
377
- } as any);
378
-
379
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
380
-
381
- expect(() => AccountInspector.getSignerPublicKeyCommitments(account)).toThrow(
382
- /zero signers/
383
- );
384
- });
385
-
386
- // 2n ** 53n is the smallest count whose Number() conversion is no longer a
387
- // safe integer (i++ would stop advancing without the ceiling guard).
388
- it.each([4294967295n, 2n ** 53n])(
389
- 'throws on an absurd signer count (%s) instead of looping',
390
- async (count) => {
391
- const { Account } = await import('@miden-sdk/miden-sdk');
392
-
393
- vi.mocked(Account.deserialize).mockReturnValueOnce({
394
- code: () => ({ hasProcedure: () => true }),
395
- storage: () => ({
396
- getItem: () => ({ toU64s: () => [2n, count, 0n, 0n] }),
397
- getMapItem: () => ({ toU64s: () => [1n, 2n, 3n, 4n], toHex: () => '0x' + 'a'.repeat(64) }),
398
- }),
399
- } as any);
400
-
401
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
402
-
403
- expect(() => AccountInspector.getSignerPublicKeyCommitments(account)).toThrow(
404
- /sanity limit/
405
- );
406
- },
407
- );
408
-
409
- it('surfaces a descriptive error for an account from a different SDK copy', async () => {
410
- const { Account } = await import('@miden-sdk/miden-sdk');
411
-
412
- // wasm-bindgen's _assertClass rejects Word instances from another
413
- // bundled SDK copy with this exact message.
414
- vi.mocked(Account.deserialize).mockReturnValueOnce({
415
- code: () => ({ hasProcedure: () => true }),
416
- storage: () => ({
417
- getItem: (slotName: string) => {
418
- if (slotName === 'miden::standards::auth::multisig::threshold_config') return { toU64s: () => [1n, 1n, 0n, 0n] };
419
- return undefined;
420
- },
421
- getMapItem: () => {
422
- throw new Error('expected instance of Word');
423
- },
424
- }),
425
- } as any);
426
-
427
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
428
-
429
- expect(() => AccountInspector.getSignerPublicKeyCommitments(account)).toThrow(
430
- /different copy of @miden-sdk\/miden-sdk/
431
- );
432
- });
433
- });
434
-
435
- describe('AccountInspector.getGuardianPublicKeyCommitment', () => {
436
- beforeEach(() => {
437
- vi.clearAllMocks();
438
- });
439
-
440
- it('returns the guardian commitment', async () => {
441
- const { Account } = await import('@miden-sdk/miden-sdk');
442
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
443
-
444
- const commitment = AccountInspector.getGuardianPublicKeyCommitment(account);
445
-
446
- expect(commitment).toBe('0xeeeeeeeeeeeeeeeeffffffffffffffff00000000000000010000000000000002');
447
- });
448
-
449
- it('rejects accounts built from a different contract version', async () => {
450
- const { Account } = await import('@miden-sdk/miden-sdk');
451
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
452
- const foreign = {
453
- ...account,
454
- code: () => ({ hasProcedure: () => false }),
455
- };
456
-
457
- expect(() => AccountInspector.getGuardianPublicKeyCommitment(foreign as never)).toThrow(
458
- /unsupported contract version/,
459
- );
460
- });
461
-
462
- it('throws when the guardian key entry is the empty word', async () => {
463
- const { Account } = await import('@miden-sdk/miden-sdk');
464
-
465
- vi.mocked(Account.deserialize).mockReturnValueOnce({
466
- code: () => ({ hasProcedure: () => true }),
467
- storage: () => ({
468
- getItem: () => ({ toU64s: () => [1n, 1n, 0n, 0n] }),
469
- getMapItem: () => ({ toU64s: () => [0n, 0n, 0n, 0n] }),
470
- }),
471
- } as any);
472
-
473
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
474
-
475
- expect(() => AccountInspector.getGuardianPublicKeyCommitment(account)).toThrow(
476
- /inconsistent account state/
477
- );
478
- });
479
-
480
- it('propagates genuine storage read failures', async () => {
481
- const { Account } = await import('@miden-sdk/miden-sdk');
482
-
483
- vi.mocked(Account.deserialize).mockReturnValueOnce({
484
- code: () => ({ hasProcedure: () => true }),
485
- storage: () => ({
486
- getItem: () => ({ toU64s: () => [1n, 1n, 0n, 0n] }),
487
- getMapItem: () => {
488
- throw new Error('storage backend exploded');
489
- },
490
- }),
491
- } as any);
492
-
493
- const account = Account.deserialize(new Uint8Array([1, 2, 3]));
494
-
495
- expect(() => AccountInspector.getGuardianPublicKeyCommitment(account)).toThrow(
496
- 'storage backend exploded'
497
- );
498
- });
499
- });
500
-
501
- describe('assertCompleteDetectedConfig', () => {
502
- const complete: DetectedMultisigConfig = {
503
- threshold: 2,
504
- numSigners: 2,
505
- signerCommitments: ['0x' + 'a'.repeat(64), '0x' + 'b'.repeat(64)],
506
- guardianCommitment: '0x' + 'c'.repeat(64),
507
- vaultBalances: [],
508
- procedureThresholds: new Map(),
509
- };
510
-
511
- it('accepts a complete config', () => {
512
- expect(() => assertCompleteDetectedConfig(complete)).not.toThrow();
513
- });
514
-
515
- it('rejects a signer set shorter than the reported count', () => {
516
- expect(() =>
517
- assertCompleteDetectedConfig({
518
- ...complete,
519
- numSigners: 3,
520
- }),
521
- ).toThrow(/incomplete signer set: storage reports 3 signers, read 2/);
522
- });
523
-
524
- it('rejects a zero signer count', () => {
525
- expect(() =>
526
- assertCompleteDetectedConfig({
527
- ...complete,
528
- numSigners: 0,
529
- signerCommitments: [],
530
- }),
531
- ).toThrow(/incomplete signer set/);
532
- });
533
-
534
- it('rejects a missing guardian commitment', () => {
535
- expect(() =>
536
- assertCompleteDetectedConfig({
537
- ...complete,
538
- guardianCommitment: null,
539
- }),
540
- ).toThrow(/missing guardian commitment/);
541
- });
542
- });