@openzeppelin/miden-multisig-client 0.12.6

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 (215) hide show
  1. package/README.md +189 -0
  2. package/dist/account/builder.d.ts +23 -0
  3. package/dist/account/builder.d.ts.map +1 -0
  4. package/dist/account/builder.js +85 -0
  5. package/dist/account/builder.js.map +1 -0
  6. package/dist/account/index.d.ts +6 -0
  7. package/dist/account/index.d.ts.map +1 -0
  8. package/dist/account/index.js +6 -0
  9. package/dist/account/index.js.map +1 -0
  10. package/dist/account/masm.d.ts +3 -0
  11. package/dist/account/masm.d.ts.map +1 -0
  12. package/dist/account/masm.js +605 -0
  13. package/dist/account/masm.js.map +1 -0
  14. package/dist/account/storage.d.ts +10 -0
  15. package/dist/account/storage.d.ts.map +1 -0
  16. package/dist/account/storage.js +56 -0
  17. package/dist/account/storage.js.map +1 -0
  18. package/dist/account.d.ts +104 -0
  19. package/dist/account.d.ts.map +1 -0
  20. package/dist/account.js +136 -0
  21. package/dist/account.js.map +1 -0
  22. package/dist/builder.d.ts +54 -0
  23. package/dist/builder.d.ts.map +1 -0
  24. package/dist/builder.js +78 -0
  25. package/dist/builder.js.map +1 -0
  26. package/dist/client.d.ts +73 -0
  27. package/dist/client.d.ts.map +1 -0
  28. package/dist/client.js +104 -0
  29. package/dist/client.js.map +1 -0
  30. package/dist/client.test.d.ts +2 -0
  31. package/dist/client.test.d.ts.map +1 -0
  32. package/dist/client.test.js +150 -0
  33. package/dist/client.test.js.map +1 -0
  34. package/dist/http.d.ts +64 -0
  35. package/dist/http.d.ts.map +1 -0
  36. package/dist/http.js +162 -0
  37. package/dist/http.js.map +1 -0
  38. package/dist/index.d.ts +53 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +52 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/inspector.d.ts +49 -0
  43. package/dist/inspector.d.ts.map +1 -0
  44. package/dist/inspector.js +120 -0
  45. package/dist/inspector.js.map +1 -0
  46. package/dist/inspector.test.d.ts +2 -0
  47. package/dist/inspector.test.d.ts.map +1 -0
  48. package/dist/inspector.test.js +205 -0
  49. package/dist/inspector.test.js.map +1 -0
  50. package/dist/keystore.d.ts +65 -0
  51. package/dist/keystore.d.ts.map +1 -0
  52. package/dist/keystore.js +121 -0
  53. package/dist/keystore.js.map +1 -0
  54. package/dist/miden.d.ts +9 -0
  55. package/dist/miden.d.ts.map +1 -0
  56. package/dist/miden.js +26 -0
  57. package/dist/miden.js.map +1 -0
  58. package/dist/multisig/helpers.d.ts +4 -0
  59. package/dist/multisig/helpers.d.ts.map +1 -0
  60. package/dist/multisig/helpers.js +21 -0
  61. package/dist/multisig/helpers.js.map +1 -0
  62. package/dist/multisig/helpers.test.d.ts +2 -0
  63. package/dist/multisig/helpers.test.d.ts.map +1 -0
  64. package/dist/multisig/helpers.test.js +94 -0
  65. package/dist/multisig/helpers.test.js.map +1 -0
  66. package/dist/multisig/metadata.d.ts +18 -0
  67. package/dist/multisig/metadata.d.ts.map +1 -0
  68. package/dist/multisig/metadata.js +100 -0
  69. package/dist/multisig/metadata.js.map +1 -0
  70. package/dist/multisig/metadata.test.d.ts +2 -0
  71. package/dist/multisig/metadata.test.d.ts.map +1 -0
  72. package/dist/multisig/metadata.test.js +323 -0
  73. package/dist/multisig/metadata.test.js.map +1 -0
  74. package/dist/multisig.d.ts +199 -0
  75. package/dist/multisig.d.ts.map +1 -0
  76. package/dist/multisig.js +821 -0
  77. package/dist/multisig.js.map +1 -0
  78. package/dist/multisig.test.d.ts +2 -0
  79. package/dist/multisig.test.d.ts.map +1 -0
  80. package/dist/multisig.test.js +1121 -0
  81. package/dist/multisig.test.js.map +1 -0
  82. package/dist/procedures.d.ts +57 -0
  83. package/dist/procedures.d.ts.map +1 -0
  84. package/dist/procedures.js +62 -0
  85. package/dist/procedures.js.map +1 -0
  86. package/dist/signer.d.ts +36 -0
  87. package/dist/signer.d.ts.map +1 -0
  88. package/dist/signer.js +68 -0
  89. package/dist/signer.js.map +1 -0
  90. package/dist/signer.test.d.ts +2 -0
  91. package/dist/signer.test.d.ts.map +1 -0
  92. package/dist/signer.test.js +117 -0
  93. package/dist/signer.test.js.map +1 -0
  94. package/dist/transaction/consumeNotes.d.ts +7 -0
  95. package/dist/transaction/consumeNotes.d.ts.map +1 -0
  96. package/dist/transaction/consumeNotes.js +28 -0
  97. package/dist/transaction/consumeNotes.js.map +1 -0
  98. package/dist/transaction/index.d.ts +7 -0
  99. package/dist/transaction/index.d.ts.map +1 -0
  100. package/dist/transaction/index.js +6 -0
  101. package/dist/transaction/index.js.map +1 -0
  102. package/dist/transaction/options.d.ts +6 -0
  103. package/dist/transaction/options.d.ts.map +1 -0
  104. package/dist/transaction/options.js +2 -0
  105. package/dist/transaction/options.js.map +1 -0
  106. package/dist/transaction/p2id.d.ts +7 -0
  107. package/dist/transaction/p2id.d.ts.map +1 -0
  108. package/dist/transaction/p2id.js +43 -0
  109. package/dist/transaction/p2id.js.map +1 -0
  110. package/dist/transaction/summary.d.ts +3 -0
  111. package/dist/transaction/summary.d.ts.map +1 -0
  112. package/dist/transaction/summary.js +6 -0
  113. package/dist/transaction/summary.js.map +1 -0
  114. package/dist/transaction/updatePsm.d.ts +7 -0
  115. package/dist/transaction/updatePsm.d.ts.map +1 -0
  116. package/dist/transaction/updatePsm.js +43 -0
  117. package/dist/transaction/updatePsm.js.map +1 -0
  118. package/dist/transaction/updateSigners.d.ts +8 -0
  119. package/dist/transaction/updateSigners.d.ts.map +1 -0
  120. package/dist/transaction/updateSigners.js +60 -0
  121. package/dist/transaction/updateSigners.js.map +1 -0
  122. package/dist/transaction.d.ts +6 -0
  123. package/dist/transaction.d.ts.map +1 -0
  124. package/dist/transaction.js +8 -0
  125. package/dist/transaction.js.map +1 -0
  126. package/dist/transaction.test.d.ts +2 -0
  127. package/dist/transaction.test.d.ts.map +1 -0
  128. package/dist/transaction.test.js +117 -0
  129. package/dist/transaction.test.js.map +1 -0
  130. package/dist/transport/http.d.ts +64 -0
  131. package/dist/transport/http.d.ts.map +1 -0
  132. package/dist/transport/http.js +162 -0
  133. package/dist/transport/http.js.map +1 -0
  134. package/dist/transport/index.d.ts +5 -0
  135. package/dist/transport/index.d.ts.map +1 -0
  136. package/dist/transport/index.js +5 -0
  137. package/dist/transport/index.js.map +1 -0
  138. package/dist/types/proposal.d.ts +74 -0
  139. package/dist/types/proposal.d.ts.map +1 -0
  140. package/dist/types/proposal.js +2 -0
  141. package/dist/types/proposal.js.map +1 -0
  142. package/dist/types.d.ts +60 -0
  143. package/dist/types.d.ts.map +1 -0
  144. package/dist/types.js +2 -0
  145. package/dist/types.js.map +1 -0
  146. package/dist/utils/encoding.d.ts +7 -0
  147. package/dist/utils/encoding.d.ts.map +1 -0
  148. package/dist/utils/encoding.js +54 -0
  149. package/dist/utils/encoding.js.map +1 -0
  150. package/dist/utils/encoding.test.d.ts +2 -0
  151. package/dist/utils/encoding.test.d.ts.map +1 -0
  152. package/dist/utils/encoding.test.js +185 -0
  153. package/dist/utils/encoding.test.js.map +1 -0
  154. package/dist/utils/index.d.ts +5 -0
  155. package/dist/utils/index.d.ts.map +1 -0
  156. package/dist/utils/index.js +5 -0
  157. package/dist/utils/index.js.map +1 -0
  158. package/dist/utils/random.d.ts +3 -0
  159. package/dist/utils/random.d.ts.map +1 -0
  160. package/dist/utils/random.js +14 -0
  161. package/dist/utils/random.js.map +1 -0
  162. package/dist/utils/signature.d.ts +12 -0
  163. package/dist/utils/signature.d.ts.map +1 -0
  164. package/dist/utils/signature.js +28 -0
  165. package/dist/utils/signature.js.map +1 -0
  166. package/dist/utils/signature.test.d.ts +2 -0
  167. package/dist/utils/signature.test.d.ts.map +1 -0
  168. package/dist/utils/signature.test.js +149 -0
  169. package/dist/utils/signature.test.js.map +1 -0
  170. package/dist/utils/word.d.ts +4 -0
  171. package/dist/utils/word.d.ts.map +1 -0
  172. package/dist/utils/word.js +8 -0
  173. package/dist/utils/word.js.map +1 -0
  174. package/dist/utils/word.test.d.ts +2 -0
  175. package/dist/utils/word.test.d.ts.map +1 -0
  176. package/dist/utils/word.test.js +54 -0
  177. package/dist/utils/word.test.js.map +1 -0
  178. package/masm/multisig.masm +423 -0
  179. package/masm/psm.masm +178 -0
  180. package/package.json +42 -0
  181. package/src/account/builder.ts +112 -0
  182. package/src/account/index.ts +15 -0
  183. package/src/account/masm.ts +606 -0
  184. package/src/account/storage.ts +70 -0
  185. package/src/client.test.ts +177 -0
  186. package/src/client.ts +129 -0
  187. package/src/index.ts +118 -0
  188. package/src/inspector.test.ts +237 -0
  189. package/src/inspector.ts +142 -0
  190. package/src/multisig/helpers.test.ts +114 -0
  191. package/src/multisig/helpers.ts +23 -0
  192. package/src/multisig.test.ts +1294 -0
  193. package/src/multisig.ts +1097 -0
  194. package/src/procedures.ts +72 -0
  195. package/src/signer.test.ts +135 -0
  196. package/src/signer.ts +75 -0
  197. package/src/transaction/consumeNotes.ts +41 -0
  198. package/src/transaction/index.ts +7 -0
  199. package/src/transaction/options.ts +7 -0
  200. package/src/transaction/p2id.ts +105 -0
  201. package/src/transaction/summary.ts +12 -0
  202. package/src/transaction/updatePsm.ts +69 -0
  203. package/src/transaction/updateSigners.ts +96 -0
  204. package/src/transaction.test.ts +136 -0
  205. package/src/transaction.ts +16 -0
  206. package/src/types/proposal.ts +80 -0
  207. package/src/types.ts +81 -0
  208. package/src/utils/encoding.test.ts +233 -0
  209. package/src/utils/encoding.ts +60 -0
  210. package/src/utils/index.ts +5 -0
  211. package/src/utils/random.ts +15 -0
  212. package/src/utils/signature.test.ts +187 -0
  213. package/src/utils/signature.ts +36 -0
  214. package/src/utils/word.test.ts +64 -0
  215. package/src/utils/word.ts +11 -0
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Account Inspector - Inspects account storage to detect multisig configuration.
3
+ */
4
+
5
+ import { Account, Word } from '@demox-labs/miden-sdk';
6
+ import { base64ToUint8Array } from './utils/encoding.js';
7
+ import { wordElementToBigInt, wordToHex } from './utils/word.js';
8
+ import { getProcedureRoot, getProcedureNames, type ProcedureName } from './procedures.js';
9
+
10
+ export interface VaultBalance {
11
+ faucetId: string;
12
+ amount: bigint;
13
+ }
14
+
15
+ export interface DetectedMultisigConfig {
16
+ threshold: number;
17
+ numSigners: number;
18
+ signerCommitments: string[];
19
+ psmEnabled: boolean;
20
+ psmCommitment: string | null;
21
+ vaultBalances: VaultBalance[];
22
+ procedureThresholds: Map<ProcedureName, number>;
23
+ }
24
+
25
+ /**
26
+ * Inspects an account to detect its multisig configuration.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * // From base64-encoded state
31
+ * const config = AccountInspector.fromBase64(stateDataBase64);
32
+ * console.log(`${config.threshold}-of-${config.numSigners} multisig`);
33
+ *
34
+ * // From Miden SDK Account
35
+ * const config = AccountInspector.fromAccount(account);
36
+ * ```
37
+ */
38
+ export class AccountInspector {
39
+ private constructor() {}
40
+
41
+ /**
42
+ * Inspect a base64-encoded serialized account.
43
+ *
44
+ * @param base64Data - Base64-encoded Account bytes
45
+ * @returns Detected multisig configuration
46
+ */
47
+ static fromBase64(base64Data: string): DetectedMultisigConfig {
48
+ const bytes = base64ToUint8Array(base64Data);
49
+ const account = Account.deserialize(bytes);
50
+ return AccountInspector.fromAccount(account);
51
+ }
52
+
53
+ /**
54
+ * Inspect a Miden SDK Account object.
55
+ *
56
+ * @param account - The Account object from Miden SDK
57
+ * @returns Detected multisig configuration
58
+ */
59
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
+ static fromAccount(account: Account): DetectedMultisigConfig {
61
+ const storage = account.storage();
62
+
63
+ const slot0 = storage.getItem(0) as Word;
64
+ const threshold = Number(wordElementToBigInt(slot0, 0));
65
+ const numSigners = Number(wordElementToBigInt(slot0, 1));
66
+
67
+ const signerCommitments: string[] = [];
68
+ for (let i = 0; i < numSigners; i++) {
69
+ try {
70
+ const key = new Word(new BigUint64Array([BigInt(i), 0n, 0n, 0n]));
71
+ const commitment = storage.getMapItem(1, key) as Word;
72
+ if (commitment) {
73
+ signerCommitments.push(wordToHex(commitment));
74
+ }
75
+ } catch (error) {
76
+ console.warn(error);
77
+ }
78
+ }
79
+
80
+ let psmEnabled = false;
81
+ let psmCommitment: string | null = null;
82
+
83
+ try {
84
+ const psmSlot0 = storage.getItem(4) as Word;
85
+ const selector = Number(wordElementToBigInt(psmSlot0, 0));
86
+ psmEnabled = selector === 1;
87
+
88
+ if (psmEnabled) {
89
+ const zeroKey = new Word(new BigUint64Array([0n, 0n, 0n, 0n]));
90
+ const psmKey = storage.getMapItem(5, zeroKey) as Word;
91
+ if (psmKey) {
92
+ psmCommitment = wordToHex(psmKey);
93
+ }
94
+ }
95
+ } catch (error) {
96
+ console.warn(error);
97
+ }
98
+
99
+ const vaultBalances: VaultBalance[] = [];
100
+ try {
101
+ const vault = account.vault();
102
+ const fungibleAssets = vault.fungibleAssets();
103
+ for (const asset of fungibleAssets) {
104
+ vaultBalances.push({
105
+ faucetId: asset.faucetId().toString(),
106
+ amount: BigInt(asset.amount()),
107
+ });
108
+ }
109
+ } catch (error) {
110
+ console.warn(error);
111
+ }
112
+
113
+ // Read procedure threshold overrides from storage slot 3
114
+ // Storage layout: slot 3 is a map of PROC_ROOT => [threshold, 0, 0, 0]
115
+ const procedureThresholds = new Map<ProcedureName, number>();
116
+ for (const procName of getProcedureNames()) {
117
+ try {
118
+ const rootHex = getProcedureRoot(procName);
119
+ const rootWord = Word.fromHex(rootHex);
120
+ const value = storage.getMapItem(3, rootWord) as Word;
121
+ if (value) {
122
+ const procThreshold = Number(wordElementToBigInt(value, 0));
123
+ if (procThreshold > 0) {
124
+ procedureThresholds.set(procName, procThreshold);
125
+ }
126
+ }
127
+ } catch {
128
+ // Procedure threshold not set - use default
129
+ }
130
+ }
131
+
132
+ return {
133
+ threshold,
134
+ numSigners,
135
+ signerCommitments,
136
+ psmEnabled,
137
+ psmCommitment,
138
+ vaultBalances,
139
+ procedureThresholds,
140
+ };
141
+ }
142
+ }
@@ -0,0 +1,114 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { computeCommitmentFromTxSummary, accountIdToHex } from './helpers.js';
3
+
4
+ vi.mock('@demox-labs/miden-sdk', () => ({
5
+ Account: {},
6
+ TransactionSummary: {
7
+ deserialize: vi.fn((bytes: Uint8Array) => ({
8
+ toCommitment: () => ({
9
+ toHex: () => '0x' + 'c'.repeat(64),
10
+ }),
11
+ })),
12
+ },
13
+ Word: {},
14
+ }));
15
+
16
+ describe('multisig helpers', () => {
17
+ beforeEach(() => {
18
+ vi.clearAllMocks();
19
+ });
20
+
21
+ describe('computeCommitmentFromTxSummary', () => {
22
+ it('computes commitment from base64 tx summary', async () => {
23
+ const base64 = btoa(String.fromCharCode(...new Uint8Array([1, 2, 3])));
24
+ const commitment = computeCommitmentFromTxSummary(base64);
25
+
26
+ expect(commitment).toBe('0x' + 'c'.repeat(64));
27
+ });
28
+
29
+ it('deserializes the tx summary bytes', async () => {
30
+ const { TransactionSummary } = await import('@demox-labs/miden-sdk');
31
+ const base64 = btoa(String.fromCharCode(...new Uint8Array([4, 5, 6])));
32
+
33
+ computeCommitmentFromTxSummary(base64);
34
+
35
+ expect(TransactionSummary.deserialize).toHaveBeenCalledWith(
36
+ new Uint8Array([4, 5, 6])
37
+ );
38
+ });
39
+
40
+ it('returns hex string with 0x prefix', () => {
41
+ const base64 = btoa(String.fromCharCode(...new Uint8Array([1])));
42
+ const commitment = computeCommitmentFromTxSummary(base64);
43
+
44
+ expect(commitment.startsWith('0x')).toBe(true);
45
+ });
46
+ });
47
+
48
+ describe('accountIdToHex', () => {
49
+ it('returns account ID string if already hex formatted', () => {
50
+ const mockAccount = {
51
+ id: () => ({
52
+ toString: () => '0xabc123',
53
+ prefix: () => ({ asInt: () => BigInt(1) }),
54
+ suffix: () => ({ asInt: () => BigInt(2) }),
55
+ }),
56
+ };
57
+
58
+ const hex = accountIdToHex(mockAccount as any);
59
+ expect(hex).toBe('0xabc123');
60
+ });
61
+
62
+ it('handles 0X prefix', () => {
63
+ const mockAccount = {
64
+ id: () => ({
65
+ toString: () => '0Xabc123',
66
+ prefix: () => ({ asInt: () => BigInt(1) }),
67
+ suffix: () => ({ asInt: () => BigInt(2) }),
68
+ }),
69
+ };
70
+
71
+ const hex = accountIdToHex(mockAccount as any);
72
+ expect(hex).toBe('0Xabc123');
73
+ });
74
+
75
+ it('constructs hex from prefix and suffix if no 0x prefix', () => {
76
+ const mockAccount = {
77
+ id: () => ({
78
+ toString: () => 'not-a-hex',
79
+ prefix: () => ({ asInt: () => BigInt('0x0102030405060708') }),
80
+ suffix: () => ({ asInt: () => BigInt('0x0a0b0c0d0e0f1011') }),
81
+ }),
82
+ };
83
+
84
+ const hex = accountIdToHex(mockAccount as any);
85
+ expect(hex).toBe('0x01020304050607080a0b0c0d0e0f10');
86
+ });
87
+
88
+ it('pads prefix to 16 hex characters', () => {
89
+ const mockAccount = {
90
+ id: () => ({
91
+ toString: () => 'not-a-hex',
92
+ prefix: () => ({ asInt: () => BigInt(1) }),
93
+ suffix: () => ({ asInt: () => BigInt(0) }),
94
+ }),
95
+ };
96
+
97
+ const hex = accountIdToHex(mockAccount as any);
98
+ expect(hex).toBe('0x000000000000000100000000000000');
99
+ });
100
+
101
+ it('produces 30-character hex (excluding 0x prefix)', () => {
102
+ const mockAccount = {
103
+ id: () => ({
104
+ toString: () => 'not-a-hex',
105
+ prefix: () => ({ asInt: () => BigInt('0xffffffffffffffff') }),
106
+ suffix: () => ({ asInt: () => BigInt('0xffffffffffffffff') }),
107
+ }),
108
+ };
109
+
110
+ const hex = accountIdToHex(mockAccount as any);
111
+ expect(hex.length).toBe(32);
112
+ });
113
+ });
114
+ });
@@ -0,0 +1,23 @@
1
+ import { Account, TransactionSummary, Word } from '@demox-labs/miden-sdk';
2
+ import { base64ToUint8Array } from '../utils/encoding.js';
3
+
4
+ export function computeCommitmentFromTxSummary(txSummaryBase64: string): string {
5
+ const bytes = base64ToUint8Array(txSummaryBase64);
6
+ const summary = TransactionSummary.deserialize(bytes);
7
+ const commitment = summary.toCommitment();
8
+ return commitment.toHex();
9
+ }
10
+
11
+ export function accountIdToHex(account: Account): string {
12
+ const accountId = account.id();
13
+ const str = accountId.toString();
14
+ if (str.startsWith('0x') || str.startsWith('0X')) {
15
+ return str;
16
+ }
17
+ const prefix = accountId.prefix().asInt();
18
+ const suffix = accountId.suffix().asInt();
19
+ const prefixHex = prefix.toString(16).padStart(16, '0');
20
+ const suffixHex = suffix.toString(16).padStart(16, '0');
21
+ return `0x${prefixHex}${suffixHex.slice(0, 14)}`;
22
+ }
23
+