@openzeppelin/miden-multisig-client 0.14.6 → 0.14.9-rc.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 (60) hide show
  1. package/README.md +114 -0
  2. package/dist/index.d.ts +4 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +4 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/multisig/config.d.ts +8 -0
  7. package/dist/multisig/config.d.ts.map +1 -0
  8. package/dist/multisig/config.js +8 -0
  9. package/dist/multisig/config.js.map +1 -0
  10. package/dist/multisig/consumeNotesErrors.d.ts +48 -0
  11. package/dist/multisig/consumeNotesErrors.d.ts.map +1 -0
  12. package/dist/multisig/consumeNotesErrors.js +58 -0
  13. package/dist/multisig/consumeNotesErrors.js.map +1 -0
  14. package/dist/multisig/consumeNotesErrors.test.d.ts +2 -0
  15. package/dist/multisig/consumeNotesErrors.test.d.ts.map +1 -0
  16. package/dist/multisig/consumeNotesErrors.test.js +28 -0
  17. package/dist/multisig/consumeNotesErrors.test.js.map +1 -0
  18. package/dist/multisig/proposal/execution.js +3 -2
  19. package/dist/multisig/proposal/execution.js.map +1 -1
  20. package/dist/multisig.d.ts +28 -5
  21. package/dist/multisig.d.ts.map +1 -1
  22. package/dist/multisig.js +235 -8
  23. package/dist/multisig.js.map +1 -1
  24. package/dist/proposal/metadata.d.ts.map +1 -1
  25. package/dist/proposal/metadata.js +18 -5
  26. package/dist/proposal/metadata.js.map +1 -1
  27. package/dist/proposal/metadata.test.d.ts +2 -0
  28. package/dist/proposal/metadata.test.d.ts.map +1 -0
  29. package/dist/proposal/metadata.test.js +87 -0
  30. package/dist/proposal/metadata.test.js.map +1 -0
  31. package/dist/transaction/consumeNotes.d.ts +13 -1
  32. package/dist/transaction/consumeNotes.d.ts.map +1 -1
  33. package/dist/transaction/consumeNotes.js +30 -13
  34. package/dist/transaction/consumeNotes.js.map +1 -1
  35. package/dist/types/proposal.d.ts +26 -5
  36. package/dist/types/proposal.d.ts.map +1 -1
  37. package/dist/types/proposal.js +10 -1
  38. package/dist/types/proposal.js.map +1 -1
  39. package/dist/types/proposal.test.d.ts +2 -0
  40. package/dist/types/proposal.test.d.ts.map +1 -0
  41. package/dist/types/proposal.test.js +56 -0
  42. package/dist/types/proposal.test.js.map +1 -0
  43. package/dist/utils/encoding.d.ts +8 -0
  44. package/dist/utils/encoding.d.ts.map +1 -1
  45. package/dist/utils/encoding.js +8 -0
  46. package/dist/utils/encoding.js.map +1 -1
  47. package/package.json +2 -2
  48. package/src/index.ts +24 -0
  49. package/src/multisig/config.ts +7 -0
  50. package/src/multisig/consumeNotesErrors.test.ts +43 -0
  51. package/src/multisig/consumeNotesErrors.ts +74 -0
  52. package/src/multisig.ts +341 -12
  53. package/src/proposal/metadata.test.ts +99 -0
  54. package/src/proposal/metadata.ts +19 -6
  55. package/src/transaction/consumeNotes.ts +40 -17
  56. package/src/types/proposal.test.ts +68 -0
  57. package/src/types/proposal.ts +42 -9
  58. package/src/utils/encoding.ts +13 -0
  59. package/src/multisig/proposal/execution.ts +0 -385
  60. package/src/multisig/proposal/parser.ts +0 -191
@@ -0,0 +1,68 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ CONSUME_NOTES_METADATA_VERSION_V2,
4
+ type ConsumeNotesProposalMetadata,
5
+ MAX_CONSUME_NOTES_METADATA_BYTES,
6
+ isConsumeNotesV1,
7
+ isConsumeNotesV2,
8
+ } from './proposal.js';
9
+
10
+ describe('consume_notes metadata v1/v2 discriminator (issue #229)', () => {
11
+ it('v1 metadata omits metadataVersion and notes on the wire', () => {
12
+ const md: ConsumeNotesProposalMetadata = {
13
+ proposalType: 'consume_notes',
14
+ description: '',
15
+ noteIds: ['0xabc', '0xdef'],
16
+ };
17
+
18
+ const json = JSON.parse(JSON.stringify(md));
19
+ expect(json.metadataVersion).toBeUndefined();
20
+ expect(json.notes).toBeUndefined();
21
+ expect(isConsumeNotesV1(md)).toBe(true);
22
+ expect(isConsumeNotesV2(md)).toBe(false);
23
+ });
24
+
25
+ it('v2 metadata round-trips with discriminator and embedded notes', () => {
26
+ const md: ConsumeNotesProposalMetadata = {
27
+ proposalType: 'consume_notes',
28
+ description: '',
29
+ noteIds: ['0xabc'],
30
+ metadataVersion: CONSUME_NOTES_METADATA_VERSION_V2,
31
+ notes: ['YmFzZTY0Tm90ZQ=='],
32
+ };
33
+
34
+ const json = JSON.stringify(md);
35
+ const parsed = JSON.parse(json) as ConsumeNotesProposalMetadata;
36
+ expect(parsed.metadataVersion).toBe(2);
37
+ expect(parsed.notes).toEqual(['YmFzZTY0Tm90ZQ==']);
38
+ expect(isConsumeNotesV2(parsed)).toBe(true);
39
+ expect(isConsumeNotesV1(parsed)).toBe(false);
40
+ });
41
+
42
+ it('explicit metadataVersion === 1 is treated as v1', () => {
43
+ const md = {
44
+ proposalType: 'consume_notes',
45
+ description: '',
46
+ noteIds: ['0xabc'],
47
+ metadataVersion: 1 as unknown as 2, // legacy explicit-v1 case
48
+ } as ConsumeNotesProposalMetadata;
49
+ expect(isConsumeNotesV1(md)).toBe(true);
50
+ expect(isConsumeNotesV2(md)).toBe(false);
51
+ });
52
+
53
+ it('unknown future version is neither v1 nor v2; dispatch handles rejection', () => {
54
+ const md = {
55
+ proposalType: 'consume_notes',
56
+ description: '',
57
+ noteIds: ['0xabc'],
58
+ metadataVersion: 99 as unknown as 2,
59
+ } as ConsumeNotesProposalMetadata;
60
+ expect(isConsumeNotesV1(md)).toBe(false);
61
+ expect(isConsumeNotesV2(md)).toBe(false);
62
+ });
63
+
64
+ it('pins MAX_CONSUME_NOTES_METADATA_BYTES at 256 KiB', () => {
65
+ expect(MAX_CONSUME_NOTES_METADATA_BYTES).toBe(256 * 1024);
66
+ expect(MAX_CONSUME_NOTES_METADATA_BYTES).toBe(262_144);
67
+ });
68
+ });
@@ -1,11 +1,21 @@
1
- import type {
2
- ProposalSignature,
3
- ProposalType as GuardianProposalType,
4
- SignatureScheme,
5
- } from '@openzeppelin/guardian-client';
1
+ import type { ProposalSignature, SignatureScheme } from '@openzeppelin/guardian-client';
6
2
  import type { ProcedureName } from '../procedures.js';
7
3
 
8
- export type ProposalType = Exclude<GuardianProposalType, 'custom'>;
4
+ /**
5
+ * Closed set of proposal types the multisig SDK models behaviorally, plus the
6
+ * `'custom'` bucket for any server-defined type the SDK does not model (issue
7
+ * #266). Defined explicitly (not derived from the now-arbitrary guardian-client
8
+ * wire union) so the exhaustive switches in the metadata codec stay sound.
9
+ */
10
+ export type ProposalType =
11
+ | 'add_signer'
12
+ | 'remove_signer'
13
+ | 'change_threshold'
14
+ | 'update_procedure_threshold'
15
+ | 'switch_guardian'
16
+ | 'consume_notes'
17
+ | 'p2id'
18
+ | 'custom';
9
19
 
10
20
  export type ProposalStatus = 'pending' | 'ready' | 'finalized';
11
21
 
@@ -49,9 +59,27 @@ export interface UpdateProcedureThresholdProposalMetadata extends BaseProposalMe
49
59
  targetThreshold: number;
50
60
  }
51
61
 
62
+ /** `consume_notes` metadata version. Absence on the wire => v1 (issue #229). */
63
+ export const CONSUME_NOTES_METADATA_VERSION_V2 = 2 as const;
64
+
65
+ /** Max serialized v2 metadata, enforced at creation (FR-011). */
66
+ export const MAX_CONSUME_NOTES_METADATA_BYTES = 256 * 1024;
67
+
52
68
  export interface ConsumeNotesProposalMetadata extends BaseProposalMetadata {
53
69
  proposalType: 'consume_notes';
54
70
  noteIds: string[];
71
+ /** Absent or `1` => v1 (legacy), `2` => v2 (issue #229). */
72
+ metadataVersion?: 1 | 2;
73
+ /** v2: base64-encoded `note.serialize()` output, index-aligned with `noteIds`. */
74
+ notes?: string[];
75
+ }
76
+
77
+ export function isConsumeNotesV2(md: ConsumeNotesProposalMetadata): boolean {
78
+ return md.metadataVersion === CONSUME_NOTES_METADATA_VERSION_V2;
79
+ }
80
+
81
+ export function isConsumeNotesV1(md: ConsumeNotesProposalMetadata): boolean {
82
+ return md.metadataVersion === undefined || md.metadataVersion === 1;
55
83
  }
56
84
 
57
85
  export interface P2IdProposalMetadata extends BaseProposalMetadata {
@@ -61,8 +89,13 @@ export interface P2IdProposalMetadata extends BaseProposalMetadata {
61
89
  amount: string;
62
90
  }
63
91
 
64
- export interface UnknownProposalMetadata extends BaseProposalMetadata {
65
- proposalType: 'unknown';
92
+ export interface CustomProposalMetadata extends BaseProposalMetadata {
93
+ proposalType: 'custom';
94
+ /** Original server-defined proposal label, e.g. "b2agg" (issue #266). Mirrors
95
+ * Rust `ProposalMetadata.proposal_type`; it is what lets a custom proposal
96
+ * round-trip back to GUARDIAN/export, so it is required in the domain model.
97
+ * Any wire-level optionality is resolved in the parser/codec boundary. */
98
+ rawProposalType: string;
66
99
  }
67
100
 
68
101
  export type ProposalMetadata =
@@ -71,7 +104,7 @@ export type ProposalMetadata =
71
104
  | UpdateProcedureThresholdProposalMetadata
72
105
  | ConsumeNotesProposalMetadata
73
106
  | P2IdProposalMetadata
74
- | UnknownProposalMetadata;
107
+ | CustomProposalMetadata;
75
108
 
76
109
  export interface Proposal {
77
110
  id: string;
@@ -40,6 +40,19 @@ export function uint8ArrayToBase64(bytes: Uint8Array): string {
40
40
  throw new Error('No base64 encoder available in this environment');
41
41
  }
42
42
 
43
+ /** Serialize a Miden `Note` to base64 (v2 `consume_notes` metadata, issue #229). */
44
+ export function noteToBase64(note: { serialize(): Uint8Array }): string {
45
+ return uint8ArrayToBase64(note.serialize());
46
+ }
47
+
48
+ /** Decode a base64 note. `noteCtor` is `Note` from `@miden-sdk/miden-sdk`. */
49
+ export function noteFromBase64<TNote>(
50
+ base64: string,
51
+ noteCtor: { deserialize(bytes: Uint8Array): TNote },
52
+ ): TNote {
53
+ return noteCtor.deserialize(base64ToUint8Array(base64));
54
+ }
55
+
43
56
  export function base64ToUint8Array(base64: string): Uint8Array {
44
57
  const binary =
45
58
  typeof atob === 'function'
@@ -1,385 +0,0 @@
1
- import { type DeltaObject, type GuardianHttpClient } from '@openzeppelin/guardian-client';
2
- import type {
3
- MidenClient,
4
- TransactionProver,
5
- TransactionRequest,
6
- } from '@miden-sdk/miden-sdk';
7
- import {
8
- AdviceMap,
9
- FeltArray,
10
- Signature,
11
- TransactionSummary,
12
- Word,
13
- } from '@miden-sdk/miden-sdk';
14
- import type { ProposalType, TransactionProposal } from '../../types.js';
15
- import {
16
- buildConsumeNotesTransactionRequest,
17
- buildP2idTransactionRequest,
18
- buildUpdateGuardianTransactionRequest,
19
- buildUpdateProcedureThresholdTransactionRequest,
20
- buildUpdateSignersTransactionRequest,
21
- } from '../../transaction.js';
22
- import { base64ToUint8Array, normalizeHexWord } from '../../utils/encoding.js';
23
- import {
24
- buildSignatureAdviceEntry,
25
- signatureHexToBytes,
26
- tryComputeEcdsaCommitmentHex,
27
- } from '../../utils/signature.js';
28
- import { computeCommitmentFromTxSummary } from '../helpers.js';
29
-
30
- interface ResolveExecutionSourceResult {
31
- delta?: DeltaObject;
32
- txSummaryBase64: string;
33
- }
34
-
35
- interface PrepareExecutionResult {
36
- txSummary: TransactionSummary;
37
- saltHex: string;
38
- txCommitmentHex: string;
39
- }
40
-
41
- interface ExecuteProposalWorkflowParams {
42
- proposal: TransactionProposal;
43
- accountId: string;
44
- threshold: number;
45
- signerCommitments: string[];
46
- guardianCommitment: string;
47
- guardianPublicKey?: string;
48
- signatureScheme: 'falcon' | 'ecdsa';
49
- getEffectiveThreshold: (proposalType: ProposalType) => number;
50
- guardian: GuardianHttpClient;
51
- midenClient: MidenClient;
52
- transactionProver?: TransactionProver | null;
53
- }
54
-
55
- export async function executeProposalWorkflow(
56
- params: ExecuteProposalWorkflowParams,
57
- ): Promise<void> {
58
- ensureProposalReady(
59
- params.proposal,
60
- params.threshold,
61
- params.getEffectiveThreshold,
62
- );
63
-
64
- const isSwitchGuardian = params.proposal.metadata.proposalType === 'switch_guardian';
65
- const executionSource = await resolveExecutionSource(
66
- params.guardian,
67
- params.accountId,
68
- params.proposal,
69
- isSwitchGuardian,
70
- );
71
- const executionData = prepareExecutionData(executionSource.txSummaryBase64);
72
-
73
- const adviceMap = buildCosignerAdviceMap(
74
- params.proposal,
75
- params.signerCommitments,
76
- executionData.txCommitmentHex,
77
- );
78
-
79
- if (!isSwitchGuardian && executionSource.delta) {
80
- await appendGuardianAckAdvice(
81
- params.guardian,
82
- executionSource.delta,
83
- params.guardianCommitment,
84
- params.guardianPublicKey,
85
- params.signatureScheme,
86
- executionData.txCommitmentHex,
87
- adviceMap,
88
- );
89
- }
90
-
91
- const finalRequest = await buildFinalRequest(
92
- params,
93
- executionData.saltHex,
94
- adviceMap,
95
- );
96
- await submitTransaction(
97
- params.midenClient,
98
- params.accountId,
99
- finalRequest,
100
- );
101
- }
102
-
103
-
104
- export async function createTransactionProposalRequest(
105
- params: ExecuteProposalWorkflowParams,
106
- ): Promise<TransactionRequest> {
107
- ensureProposalReady(
108
- params.proposal,
109
- params.threshold,
110
- params.getEffectiveThreshold,
111
- );
112
-
113
- const isSwitchGuardian = params.proposal.metadata.proposalType === 'switch_guardian';
114
- const executionSource = await resolveExecutionSource(
115
- params.guardian,
116
- params.accountId,
117
- params.proposal,
118
- isSwitchGuardian,
119
- );
120
- const executionData = prepareExecutionData(executionSource.txSummaryBase64);
121
-
122
- const adviceMap = buildCosignerAdviceMap(
123
- params.proposal,
124
- params.signerCommitments,
125
- executionData.txCommitmentHex,
126
- );
127
-
128
- if (!isSwitchGuardian && executionSource.delta) {
129
- await appendGuardianAckAdvice(
130
- params.guardian,
131
- executionSource.delta,
132
- params.guardianCommitment,
133
- params.guardianPublicKey,
134
- params.signatureScheme,
135
- executionData.txCommitmentHex,
136
- adviceMap,
137
- );
138
- }
139
-
140
- return await buildFinalRequest(
141
- params,
142
- executionData.saltHex,
143
- adviceMap,
144
- );
145
- }
146
-
147
- function ensureProposalReady(
148
- proposal: TransactionProposal,
149
- defaultThreshold: number,
150
- getEffectiveThreshold: (proposalType: ProposalType) => number,
151
- ): void {
152
- const proposalType = proposal.metadata?.proposalType;
153
- const effectiveThreshold = proposalType
154
- ? getEffectiveThreshold(proposalType)
155
- : defaultThreshold;
156
-
157
- if (proposal.signatures.length < effectiveThreshold) {
158
- throw new Error('Proposal is not ready for execution. Still pending signatures.');
159
- }
160
- }
161
-
162
- async function resolveExecutionSource(
163
- guardian: GuardianHttpClient,
164
- accountId: string,
165
- proposal: TransactionProposal,
166
- isSwitchGuardian: boolean,
167
- ): Promise<ResolveExecutionSourceResult> {
168
- if (isSwitchGuardian) {
169
- return { txSummaryBase64: proposal.txSummary };
170
- }
171
-
172
- const deltas = await guardian.getDeltaProposals(accountId);
173
- const delta = deltas.find(
174
- (d) => computeCommitmentFromTxSummary(d.deltaPayload.txSummary.data) === proposal.commitment,
175
- );
176
-
177
- if (!delta) {
178
- throw new Error(`Proposal not found on server: ${proposal.commitment}`);
179
- }
180
-
181
- return {
182
- delta,
183
- txSummaryBase64: delta.deltaPayload.txSummary.data,
184
- };
185
- }
186
-
187
- function prepareExecutionData(txSummaryBase64: string): PrepareExecutionResult {
188
- const txSummaryBytes = base64ToUint8Array(txSummaryBase64);
189
- const txSummary = TransactionSummary.deserialize(txSummaryBytes);
190
- const saltHex = txSummary.salt().toHex();
191
- const txCommitmentHex = txSummary.toCommitment().toHex();
192
- return { txSummary, saltHex, txCommitmentHex };
193
- }
194
-
195
- function buildCosignerAdviceMap(
196
- proposal: TransactionProposal,
197
- signerCommitments: string[],
198
- txCommitmentHex: string,
199
- ): AdviceMap {
200
- const adviceMap = new AdviceMap();
201
- const normalizedSignerCommitments = new Set(
202
- signerCommitments.map((c) => normalizeHexWord(c)),
203
- );
204
-
205
- for (const cosignerSig of proposal.signatures) {
206
- let signerCommitmentHex = normalizeHexWord(cosignerSig.signerId);
207
- if (cosignerSig.signature.scheme === 'ecdsa' && cosignerSig.signature.publicKey) {
208
- const derived = tryComputeEcdsaCommitmentHex(cosignerSig.signature.publicKey);
209
- if (derived && derived !== signerCommitmentHex) {
210
- if (!normalizedSignerCommitments.has(derived)) {
211
- throw new Error(
212
- `ECDSA public key commitment mismatch: derived commitment ${derived} is not in signerCommitments.`,
213
- );
214
- }
215
- signerCommitmentHex = derived;
216
- }
217
- }
218
-
219
- const signerCommitment = Word.fromHex(signerCommitmentHex);
220
- const sigBytes = signatureHexToBytes(
221
- cosignerSig.signature.signature,
222
- cosignerSig.signature.scheme,
223
- );
224
- const signature = Signature.deserialize(sigBytes);
225
- const txCommitment = Word.fromHex(normalizeHexWord(txCommitmentHex));
226
- const ecdsaPublicKey =
227
- cosignerSig.signature.scheme === 'ecdsa'
228
- ? cosignerSig.signature.publicKey
229
- : undefined;
230
- const isEcdsa = cosignerSig.signature.scheme === 'ecdsa' && Boolean(ecdsaPublicKey);
231
-
232
- const { key, values } = buildSignatureAdviceEntry(
233
- signerCommitment,
234
- txCommitment,
235
- signature,
236
- ecdsaPublicKey,
237
- isEcdsa ? cosignerSig.signature.signature : undefined,
238
- );
239
- adviceMap.insert(key, new FeltArray(values));
240
- }
241
-
242
- return adviceMap;
243
- }
244
-
245
- async function appendGuardianAckAdvice(
246
- guardian: GuardianHttpClient,
247
- delta: DeltaObject,
248
- guardianCommitmentHex: string,
249
- guardianPublicKey: string | undefined,
250
- defaultAckScheme: 'falcon' | 'ecdsa',
251
- txCommitmentHex: string,
252
- adviceMap: AdviceMap,
253
- ): Promise<void> {
254
- const executionDelta = {
255
- ...delta,
256
- deltaPayload: delta.deltaPayload.txSummary,
257
- };
258
-
259
- const pushResult = await guardian.pushDelta(executionDelta);
260
- const ackSigHex = pushResult.ackSig;
261
- if (!ackSigHex) {
262
- throw new Error('GUARDIAN did not return acknowledgment signature');
263
- }
264
-
265
- const guardianAckScheme: 'ecdsa' | 'falcon' =
266
- (pushResult.ackScheme as 'ecdsa' | 'falcon') || defaultAckScheme;
267
- const ackPubkey = pushResult.ackPubkey || guardianPublicKey;
268
- const normalizedGuardianCommitment = normalizeHexWord(guardianCommitmentHex);
269
-
270
- if (guardianAckScheme === 'ecdsa' && ackPubkey) {
271
- const derived = tryComputeEcdsaCommitmentHex(ackPubkey);
272
- if (derived && derived !== normalizedGuardianCommitment) {
273
- throw new Error('GUARDIAN public key commitment mismatch');
274
- }
275
- }
276
-
277
- const guardianCommitment = Word.fromHex(normalizedGuardianCommitment);
278
- const ackSigBytes = signatureHexToBytes(ackSigHex, guardianAckScheme);
279
- const ackSignature = Signature.deserialize(ackSigBytes);
280
- const txCommitment = Word.fromHex(normalizeHexWord(txCommitmentHex));
281
- const isAckEcdsa = guardianAckScheme === 'ecdsa' && ackPubkey;
282
- const { key, values } = buildSignatureAdviceEntry(
283
- guardianCommitment,
284
- txCommitment,
285
- ackSignature,
286
- isAckEcdsa ? ackPubkey : undefined,
287
- isAckEcdsa ? ackSigHex : undefined,
288
- );
289
- adviceMap.insert(key, new FeltArray(values));
290
- }
291
-
292
- async function buildFinalRequest(
293
- params: ExecuteProposalWorkflowParams,
294
- saltHex: string,
295
- adviceMap: AdviceMap,
296
- ): Promise<TransactionRequest> {
297
- const metadata = params.proposal.metadata;
298
- const normalizedSalt = Word.fromHex(normalizeHexWord(saltHex));
299
-
300
- switch (metadata.proposalType) {
301
- case 'consume_notes': {
302
- if (!metadata.noteIds || metadata.noteIds.length === 0) {
303
- throw new Error(
304
- 'Proposal missing noteIds. Was it created with createConsumeNotesProposal?',
305
- );
306
- }
307
- const { request } = await buildConsumeNotesTransactionRequest(
308
- params.midenClient,
309
- metadata.noteIds,
310
- { salt: normalizedSalt, signatureAdviceMap: adviceMap },
311
- );
312
- return request;
313
- }
314
- case 'switch_guardian': {
315
- if (!metadata.newGuardianPubkey) {
316
- throw new Error(
317
- 'Proposal missing newGuardianPubkey. Was it created with createSwitchGuardianProposal?',
318
- );
319
- }
320
- const { request } = await buildUpdateGuardianTransactionRequest(
321
- params.midenClient,
322
- metadata.newGuardianPubkey,
323
- {
324
- salt: normalizedSalt,
325
- signatureAdviceMap: adviceMap,
326
- signatureScheme: params.signatureScheme,
327
- },
328
- );
329
- return request;
330
- }
331
- case 'update_procedure_threshold': {
332
- const { request } = await buildUpdateProcedureThresholdTransactionRequest(
333
- params.midenClient,
334
- metadata.targetProcedure,
335
- metadata.targetThreshold,
336
- {
337
- salt: normalizedSalt,
338
- signatureAdviceMap: adviceMap,
339
- signatureScheme: params.signatureScheme,
340
- },
341
- );
342
- return request;
343
- }
344
- case 'p2id': {
345
- if (!metadata.recipientId || !metadata.faucetId || !metadata.amount) {
346
- throw new Error(
347
- 'Proposal missing P2ID metadata (recipientId, faucetId, amount). Was it created with createP2idProposal?',
348
- );
349
- }
350
- const { request } = buildP2idTransactionRequest(
351
- params.accountId,
352
- metadata.recipientId,
353
- metadata.faucetId,
354
- BigInt(metadata.amount),
355
- { salt: normalizedSalt, signatureAdviceMap: adviceMap },
356
- );
357
- return request;
358
- }
359
- case 'unknown':
360
- throw new Error(
361
- 'Cannot execute proposal with unknown type. The proposal must have been imported without proper metadata.',
362
- );
363
- default: {
364
- const { request } = await buildUpdateSignersTransactionRequest(
365
- params.midenClient,
366
- metadata.targetThreshold,
367
- metadata.targetSignerCommitments,
368
- {
369
- salt: normalizedSalt,
370
- signatureAdviceMap: adviceMap,
371
- signatureScheme: params.signatureScheme,
372
- },
373
- );
374
- return request;
375
- }
376
- }
377
- }
378
-
379
- async function submitTransaction(
380
- midenClient: MidenClient,
381
- accountIdHex: string,
382
- request: TransactionRequest,
383
- ): Promise<void> {
384
- await midenClient.transactions.submit(accountIdHex, request);
385
- }