@openzeppelin/miden-multisig-client 0.18.0-rc.2 → 0.18.0-rc.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.
- package/README.md +46 -4
- package/dist/account/builder.d.ts +3 -4
- package/dist/account/builder.d.ts.map +1 -1
- package/dist/account/builder.js +6 -13
- package/dist/account/builder.js.map +1 -1
- package/dist/client.d.ts +11 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +8 -3
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/multisig.d.ts +40 -9
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +97 -108
- package/dist/multisig.js.map +1 -1
- package/dist/procedures.d.ts +5 -5
- package/dist/procedures.js +5 -5
- package/dist/recovery/proposalNoteImport.d.ts +5 -6
- package/dist/recovery/proposalNoteImport.d.ts.map +1 -1
- package/dist/recovery/proposalNoteImport.js +12 -13
- package/dist/recovery/proposalNoteImport.js.map +1 -1
- package/dist/recovery/publicNoteBackfill.d.ts +2 -3
- package/dist/recovery/publicNoteBackfill.d.ts.map +1 -1
- package/dist/recovery/publicNoteBackfill.js +4 -5
- package/dist/recovery/publicNoteBackfill.js.map +1 -1
- package/dist/transaction/authArgs.d.ts +2 -3
- package/dist/transaction/authArgs.d.ts.map +1 -1
- package/dist/transaction/authArgs.js +7 -14
- package/dist/transaction/authArgs.js.map +1 -1
- package/dist/transaction/consumeNotes.d.ts +4 -12
- package/dist/transaction/consumeNotes.d.ts.map +1 -1
- package/dist/transaction/consumeNotes.js +10 -4
- package/dist/transaction/consumeNotes.js.map +1 -1
- package/dist/transaction/noteAuthentication.d.ts +2 -3
- package/dist/transaction/noteAuthentication.d.ts.map +1 -1
- package/dist/transaction/noteAuthentication.js +11 -11
- package/dist/transaction/noteAuthentication.js.map +1 -1
- package/dist/transaction/options.d.ts +0 -7
- package/dist/transaction/options.d.ts.map +1 -1
- package/dist/transaction/p2id.d.ts +2 -3
- package/dist/transaction/p2id.d.ts.map +1 -1
- package/dist/transaction/p2id.js.map +1 -1
- package/dist/transaction/summary.d.ts +8 -14
- package/dist/transaction/summary.d.ts.map +1 -1
- package/dist/transaction/summary.js +64 -20
- package/dist/transaction/summary.js.map +1 -1
- package/dist/transaction/updateGuardian.d.ts +3 -7
- package/dist/transaction/updateGuardian.d.ts.map +1 -1
- package/dist/transaction/updateGuardian.js +3 -4
- package/dist/transaction/updateGuardian.js.map +1 -1
- package/dist/transaction/updateProcedureThreshold.d.ts +3 -8
- package/dist/transaction/updateProcedureThreshold.d.ts.map +1 -1
- package/dist/transaction/updateProcedureThreshold.js +3 -4
- package/dist/transaction/updateProcedureThreshold.js.map +1 -1
- package/dist/transaction/updateSigners.d.ts +3 -8
- package/dist/transaction/updateSigners.d.ts.map +1 -1
- package/dist/transaction/updateSigners.js +3 -4
- package/dist/transaction/updateSigners.js.map +1 -1
- package/package.json +4 -4
- package/src/account/builder.ts +6 -13
- package/src/client.ts +13 -10
- package/src/config.ts +14 -0
- package/src/index.ts +2 -3
- package/src/multisig.ts +125 -143
- package/src/procedures.ts +5 -5
- package/src/recovery/proposalNoteImport.ts +13 -15
- package/src/recovery/publicNoteBackfill.ts +6 -6
- package/src/transaction/authArgs.ts +15 -21
- package/src/transaction/consumeNotes.ts +6 -34
- package/src/transaction/noteAuthentication.ts +18 -13
- package/src/transaction/options.ts +0 -9
- package/src/transaction/p2id.ts +2 -3
- package/src/transaction/summary.ts +27 -69
- package/src/transaction/updateGuardian.ts +5 -23
- package/src/transaction/updateProcedureThreshold.ts +5 -25
- package/src/transaction/updateSigners.ts +5 -22
- package/dist/raw-client.d.ts +0 -14
- package/dist/raw-client.d.ts.map +0 -1
- package/dist/raw-client.js +0 -60
- package/dist/raw-client.js.map +0 -1
- package/src/raw-client.ts +0 -89
|
@@ -15,17 +15,16 @@ import {
|
|
|
15
15
|
InputNote,
|
|
16
16
|
type InputNoteRecord,
|
|
17
17
|
InputNoteState,
|
|
18
|
+
type MidenClient,
|
|
18
19
|
Note,
|
|
19
20
|
type NoteAssets,
|
|
20
21
|
NoteDetails,
|
|
21
22
|
NoteFile,
|
|
22
|
-
NoteFilter,
|
|
23
|
-
NoteFilterTypes,
|
|
24
23
|
type NoteInclusionProof,
|
|
25
24
|
RpcClient,
|
|
26
25
|
} from '@miden-sdk/miden-sdk';
|
|
27
26
|
|
|
28
|
-
import {
|
|
27
|
+
import { requireMidenRpcEndpoint } from '../config.js';
|
|
29
28
|
import { resolveRpcConfig, type RpcConfig } from '../rpc/config.js';
|
|
30
29
|
import { isTransientRpcError } from '../rpc/errors.js';
|
|
31
30
|
import { retryRpcRead } from '../rpc/retry.js';
|
|
@@ -176,10 +175,10 @@ function recordKeys(record: InputNoteRecord): string[] {
|
|
|
176
175
|
* Shared by the recovery primitives (proposal import and backfill).
|
|
177
176
|
*/
|
|
178
177
|
export async function collectExistingRecords(
|
|
179
|
-
|
|
178
|
+
midenClient: MidenClient,
|
|
180
179
|
): Promise<Map<string, InputNoteRecord>> {
|
|
181
180
|
const existing = new Map<string, InputNoteRecord>();
|
|
182
|
-
const records = await
|
|
181
|
+
const records = await midenClient.notes.list();
|
|
183
182
|
for (const record of records) {
|
|
184
183
|
for (const key of recordKeys(record)) {
|
|
185
184
|
existing.set(key, record);
|
|
@@ -196,7 +195,7 @@ export async function collectExistingRecords(
|
|
|
196
195
|
* re-check).
|
|
197
196
|
*/
|
|
198
197
|
export async function importNoteWithProof(
|
|
199
|
-
|
|
198
|
+
midenClient: MidenClient,
|
|
200
199
|
source: NoteImportSource,
|
|
201
200
|
idHex: string,
|
|
202
201
|
note: Note,
|
|
@@ -204,7 +203,7 @@ export async function importNoteWithProof(
|
|
|
204
203
|
): Promise<{ outcome: NoteImportOutcome; wasImported: boolean }> {
|
|
205
204
|
try {
|
|
206
205
|
const inputNote = InputNote.authenticated(note, proof);
|
|
207
|
-
await
|
|
206
|
+
await midenClient.notes.import(NoteFile.fromInputNote(inputNote));
|
|
208
207
|
return {
|
|
209
208
|
outcome: { identifier: idHex, source, status: 'imported' },
|
|
210
209
|
wasImported: true,
|
|
@@ -239,7 +238,7 @@ export async function importNoteWithProof(
|
|
|
239
238
|
* it flags the outcome's classification as unconfirmed instead.
|
|
240
239
|
*/
|
|
241
240
|
export async function reclassifyConsumedImports(
|
|
242
|
-
|
|
241
|
+
midenClient: MidenClient,
|
|
243
242
|
imported: Array<{ index: number; idHex: string; detailsKey: string }>,
|
|
244
243
|
outcomes: NoteImportOutcome[],
|
|
245
244
|
): Promise<void> {
|
|
@@ -247,7 +246,7 @@ export async function reclassifyConsumedImports(
|
|
|
247
246
|
return;
|
|
248
247
|
}
|
|
249
248
|
try {
|
|
250
|
-
const records = await
|
|
249
|
+
const records = await midenClient.notes.list();
|
|
251
250
|
const byId = new Map<string, InputNoteRecord>();
|
|
252
251
|
const byDetailsKey = new Map<string, InputNoteRecord>();
|
|
253
252
|
for (const record of records) {
|
|
@@ -328,14 +327,13 @@ export async function reclassifyConsumedImports(
|
|
|
328
327
|
* ```
|
|
329
328
|
*/
|
|
330
329
|
export async function importNotesFromProposals(
|
|
331
|
-
midenClient:
|
|
330
|
+
midenClient: MidenClient,
|
|
332
331
|
proposals: ReadonlyArray<Pick<Proposal, 'id' | 'metadata'>>,
|
|
333
332
|
options: ImportNotesFromProposalsOptions,
|
|
334
333
|
): Promise<NoteImportOutcome[]> {
|
|
335
334
|
const midenRpcEndpoint = requireMidenRpcEndpoint(options.midenRpcEndpoint);
|
|
336
335
|
const rpcConfig = resolveRpcConfig(options.rpc);
|
|
337
336
|
throwIfCancelled(options.cancelled);
|
|
338
|
-
const webClient = await getRawMidenClient(midenClient, midenRpcEndpoint);
|
|
339
337
|
|
|
340
338
|
const outcomes: NoteImportOutcome[] = [];
|
|
341
339
|
|
|
@@ -413,7 +411,7 @@ export async function importNotesFromProposals(
|
|
|
413
411
|
|
|
414
412
|
let existing: Map<string, InputNoteRecord>;
|
|
415
413
|
try {
|
|
416
|
-
existing = await collectExistingRecords(
|
|
414
|
+
existing = await collectExistingRecords(midenClient);
|
|
417
415
|
} catch (error) {
|
|
418
416
|
const reason = `failed to read local store: ${errorDetail(error)}`;
|
|
419
417
|
for (const candidate of decoded) {
|
|
@@ -496,7 +494,7 @@ export async function importNotesFromProposals(
|
|
|
496
494
|
const proof = proofs.get(candidate.idHex);
|
|
497
495
|
if (proof) {
|
|
498
496
|
const { outcome, wasImported } = await importNoteWithProof(
|
|
499
|
-
|
|
497
|
+
midenClient,
|
|
500
498
|
'proposal',
|
|
501
499
|
candidate.idHex,
|
|
502
500
|
candidate.note,
|
|
@@ -519,7 +517,7 @@ export async function importNotesFromProposals(
|
|
|
519
517
|
// create a permanent user-source tag that the transport backfill
|
|
520
518
|
// also re-drains, and that would outlive even a failed import.)
|
|
521
519
|
const details = new NoteDetails(candidate.note.assets(), candidate.note.recipient());
|
|
522
|
-
await
|
|
520
|
+
await midenClient.notes.import(
|
|
523
521
|
NoteFile.fromExpectedNote(details, candidate.note.metadata().tag(), 0),
|
|
524
522
|
);
|
|
525
523
|
outcomes.push({
|
|
@@ -542,7 +540,7 @@ export async function importNotesFromProposals(
|
|
|
542
540
|
}
|
|
543
541
|
|
|
544
542
|
throwIfCancelled(options.cancelled);
|
|
545
|
-
await reclassifyConsumedImports(
|
|
543
|
+
await reclassifyConsumedImports(midenClient, imported, outcomes);
|
|
546
544
|
|
|
547
545
|
return outcomes;
|
|
548
546
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
type CommittedNote,
|
|
16
16
|
Endpoint,
|
|
17
17
|
type InputNoteRecord,
|
|
18
|
+
type MidenClient,
|
|
18
19
|
type Note,
|
|
19
20
|
type NoteInclusionProof,
|
|
20
21
|
NoteScript,
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
type NoteImportOutcome,
|
|
33
34
|
reclassifyConsumedImports,
|
|
34
35
|
} from './proposalNoteImport.js';
|
|
35
|
-
import {
|
|
36
|
+
import { requireMidenRpcEndpoint } from '../config.js';
|
|
36
37
|
import { resolveRpcConfig, type RpcConfig } from '../rpc/config.js';
|
|
37
38
|
import { isTransientRpcError } from '../rpc/errors.js';
|
|
38
39
|
import { retryRpcRead } from '../rpc/retry.js';
|
|
@@ -235,12 +236,11 @@ export interface BackfillPublicNotesOptions {
|
|
|
235
236
|
* ```
|
|
236
237
|
*/
|
|
237
238
|
export async function backfillPublicNotesByTag(
|
|
238
|
-
midenClient:
|
|
239
|
+
midenClient: MidenClient,
|
|
239
240
|
options: BackfillPublicNotesOptions,
|
|
240
241
|
): Promise<PublicBackfillReport> {
|
|
241
242
|
const midenRpcEndpoint = requireMidenRpcEndpoint(options.midenRpcEndpoint);
|
|
242
243
|
const rpcConfig = resolveRpcConfig(options.rpc);
|
|
243
|
-
const webClient = await getRawMidenClient(midenClient, midenRpcEndpoint);
|
|
244
244
|
const rpcClient = new RpcClient(new Endpoint(midenRpcEndpoint));
|
|
245
245
|
// Parse eagerly so a malformed account ID throws before any network work.
|
|
246
246
|
AccountId.fromHex(options.accountId);
|
|
@@ -426,7 +426,7 @@ export async function backfillPublicNotesByTag(
|
|
|
426
426
|
|
|
427
427
|
let existing: Map<string, InputNoteRecord>;
|
|
428
428
|
try {
|
|
429
|
-
existing = await collectExistingRecords(
|
|
429
|
+
existing = await collectExistingRecords(midenClient);
|
|
430
430
|
} catch (error) {
|
|
431
431
|
const reason = `failed to read local store: ${errorDetail(error)}`;
|
|
432
432
|
for (const candidate of pending) {
|
|
@@ -480,7 +480,7 @@ export async function backfillPublicNotesByTag(
|
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
482
|
const { outcome, wasImported } = await importNoteWithProof(
|
|
483
|
-
|
|
483
|
+
midenClient,
|
|
484
484
|
'backfill',
|
|
485
485
|
candidate.idHex,
|
|
486
486
|
candidate.note,
|
|
@@ -496,7 +496,7 @@ export async function backfillPublicNotesByTag(
|
|
|
496
496
|
outcomes.push(outcome);
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
-
await reclassifyConsumedImports(
|
|
499
|
+
await reclassifyConsumedImports(midenClient, imported, outcomes);
|
|
500
500
|
|
|
501
501
|
return buildReport();
|
|
502
502
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
Felt,
|
|
3
|
+
MidenClient,
|
|
4
|
+
TransactionRequest,
|
|
5
|
+
TransactionRequestBuilder,
|
|
6
|
+
Word,
|
|
7
|
+
} from '@miden-sdk/miden-sdk';
|
|
8
|
+
import { Word as WordType } from '@miden-sdk/miden-sdk';
|
|
3
9
|
import { MultisigAuthArgsMissingError } from '../multisig/authArgErrors.js';
|
|
4
|
-
import { getRawMidenClient, isPublicMidenClient, type RawClientSource } from '../raw-client.js';
|
|
5
10
|
import { normalizeHexWord } from '../utils/encoding.js';
|
|
6
11
|
import { randomWord } from '../utils/random.js';
|
|
7
12
|
import type { MultisigRequestOptions } from './options.js';
|
|
@@ -38,28 +43,17 @@ export interface MultisigRequestDraft {
|
|
|
38
43
|
* the hex rather than taken from the caller, and nothing frees it afterwards.
|
|
39
44
|
*/
|
|
40
45
|
export async function multisigRequestBuilder(
|
|
41
|
-
client:
|
|
46
|
+
client: MidenClient,
|
|
42
47
|
options: MultisigRequestOptions,
|
|
43
48
|
): Promise<MultisigRequestDraft> {
|
|
44
|
-
const { accountId, boundBlockNum, approvalExpirationDelta
|
|
49
|
+
const { accountId, boundBlockNum, approvalExpirationDelta } = options;
|
|
45
50
|
assertApprovalExpirationDelta(approvalExpirationDelta);
|
|
46
51
|
const saltHex = normalizeHexWord(options.salt ? options.salt.toHex() : randomWord().toHex());
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
approvalExpirationDelta,
|
|
53
|
-
});
|
|
54
|
-
return { builder, saltHex };
|
|
55
|
-
}
|
|
56
|
-
const rawClient = await getRawMidenClient(client, midenRpcEndpoint);
|
|
57
|
-
const builder = await rawClient.feeAwareTransactionRequestBuilder(
|
|
58
|
-
AccountId.fromHex(accountId),
|
|
59
|
-
approvalExpirationDelta ?? null,
|
|
60
|
-
salt,
|
|
61
|
-
boundBlockNum ?? null,
|
|
62
|
-
);
|
|
52
|
+
const builder = await client.feeAwareTransactionRequestBuilder(accountId, {
|
|
53
|
+
feeConversionSalt: WordType.fromHex(saltHex),
|
|
54
|
+
boundBlockNum,
|
|
55
|
+
approvalExpirationDelta,
|
|
56
|
+
});
|
|
63
57
|
return { builder, saltHex };
|
|
64
58
|
}
|
|
65
59
|
|
|
@@ -1,32 +1,15 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
MidenClient,
|
|
3
|
-
Note,
|
|
4
|
-
TransactionRequest,
|
|
5
|
-
WasmWebClient,
|
|
6
|
-
Word,
|
|
7
|
-
} from '@miden-sdk/miden-sdk';
|
|
1
|
+
import type { MidenClient, Note, TransactionRequest, Word } from '@miden-sdk/miden-sdk';
|
|
8
2
|
import { NoteAndArgs, NoteAndArgsArray } from '@miden-sdk/miden-sdk';
|
|
9
3
|
import { LegacyConsumeNotesNoteMissingError } from '../multisig/consumeNotesErrors.js';
|
|
10
|
-
import { getRawMidenClient } from '../raw-client.js';
|
|
11
4
|
import { buildMultisigRequest, multisigRequestBuilder } from './authArgs.js';
|
|
12
|
-
import type {
|
|
5
|
+
import type { MultisigRequestOptions } from './options.js';
|
|
13
6
|
|
|
14
7
|
/**
|
|
15
8
|
* Build a consume-notes request from loaded `Note` objects (no local-store
|
|
16
9
|
* read). v2 verification path for issue #229.
|
|
17
10
|
*/
|
|
18
|
-
export function buildConsumeNotesTransactionRequestFromNotes(
|
|
19
|
-
client: MidenClient,
|
|
20
|
-
notes: Note[],
|
|
21
|
-
options: MidenClientMultisigRequestOptions,
|
|
22
|
-
): Promise<{ request: TransactionRequest; salt: Word }>;
|
|
23
|
-
export function buildConsumeNotesTransactionRequestFromNotes(
|
|
24
|
-
client: WasmWebClient,
|
|
25
|
-
notes: Note[],
|
|
26
|
-
options: MultisigRequestOptions,
|
|
27
|
-
): Promise<{ request: TransactionRequest; salt: Word }>;
|
|
28
11
|
export async function buildConsumeNotesTransactionRequestFromNotes(
|
|
29
|
-
client: MidenClient
|
|
12
|
+
client: MidenClient,
|
|
30
13
|
notes: Note[],
|
|
31
14
|
options: MultisigRequestOptions,
|
|
32
15
|
): Promise<{ request: TransactionRequest; salt: Word }> {
|
|
@@ -53,18 +36,8 @@ export async function buildConsumeNotesTransactionRequestFromNotes(
|
|
|
53
36
|
* Legacy/creation adapter: fetches notes from the local store and delegates
|
|
54
37
|
* to the from-notes variant. v2 verification MUST NOT call this.
|
|
55
38
|
*/
|
|
56
|
-
export function buildConsumeNotesTransactionRequest(
|
|
57
|
-
client: MidenClient,
|
|
58
|
-
noteIds: string[],
|
|
59
|
-
options: MidenClientMultisigRequestOptions,
|
|
60
|
-
): Promise<{ request: TransactionRequest; salt: Word }>;
|
|
61
|
-
export function buildConsumeNotesTransactionRequest(
|
|
62
|
-
client: WasmWebClient,
|
|
63
|
-
noteIds: string[],
|
|
64
|
-
options: MultisigRequestOptions,
|
|
65
|
-
): Promise<{ request: TransactionRequest; salt: Word }>;
|
|
66
39
|
export async function buildConsumeNotesTransactionRequest(
|
|
67
|
-
client: MidenClient
|
|
40
|
+
client: MidenClient,
|
|
68
41
|
noteIds: string[],
|
|
69
42
|
options: MultisigRequestOptions,
|
|
70
43
|
): Promise<{ request: TransactionRequest; salt: Word }> {
|
|
@@ -72,15 +45,14 @@ export async function buildConsumeNotesTransactionRequest(
|
|
|
72
45
|
throw new Error('At least one note ID is required');
|
|
73
46
|
}
|
|
74
47
|
|
|
75
|
-
const rawClient = await getRawMidenClient(client, options.midenRpcEndpoint);
|
|
76
48
|
const notes: Note[] = [];
|
|
77
49
|
for (const noteIdHex of noteIds) {
|
|
78
|
-
const inputNoteRecord = await
|
|
50
|
+
const inputNoteRecord = await client.notes.get(noteIdHex);
|
|
79
51
|
if (!inputNoteRecord) {
|
|
80
52
|
throw new LegacyConsumeNotesNoteMissingError(noteIdHex);
|
|
81
53
|
}
|
|
82
54
|
notes.push(inputNoteRecord.toNote());
|
|
83
55
|
}
|
|
84
56
|
|
|
85
|
-
return buildConsumeNotesTransactionRequestFromNotes(
|
|
57
|
+
return buildConsumeNotesTransactionRequestFromNotes(client, notes, options);
|
|
86
58
|
}
|
|
@@ -13,11 +13,16 @@
|
|
|
13
13
|
* {@link ensureNotesAuthenticated} first, so the executed transaction is the
|
|
14
14
|
* one the cosigners signed regardless of what each store held before.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
Endpoint,
|
|
18
|
+
type MidenClient,
|
|
19
|
+
type Note,
|
|
20
|
+
type NoteInclusionProof,
|
|
21
|
+
RpcClient,
|
|
22
|
+
} from '@miden-sdk/miden-sdk';
|
|
17
23
|
|
|
24
|
+
import { requireMidenRpcEndpoint } from '../config.js';
|
|
18
25
|
import { ConsumeNoteNotAuthenticatedError } from '../multisig/consumeNotesErrors.js';
|
|
19
|
-
import type { RawClientSource } from '../raw-client.js';
|
|
20
|
-
import { getRawMidenClient } from '../raw-client.js';
|
|
21
26
|
import { importNoteWithProof } from '../recovery/proposalNoteImport.js';
|
|
22
27
|
import { resolveRpcConfig, type RpcConfig } from '../rpc/config.js';
|
|
23
28
|
import { retryRpcRead } from '../rpc/retry.js';
|
|
@@ -44,19 +49,19 @@ export interface EnsureNotesAuthenticatedOptions {
|
|
|
44
49
|
* record still lacks authentication after a sync.
|
|
45
50
|
*/
|
|
46
51
|
export async function ensureNotesAuthenticated(
|
|
47
|
-
midenClient:
|
|
52
|
+
midenClient: MidenClient,
|
|
48
53
|
notes: readonly Note[],
|
|
49
54
|
options: EnsureNotesAuthenticatedOptions,
|
|
50
55
|
): Promise<void> {
|
|
51
|
-
const
|
|
52
|
-
const pending = await unauthenticatedNotes(
|
|
56
|
+
const midenRpcEndpoint = requireMidenRpcEndpoint(options.midenRpcEndpoint);
|
|
57
|
+
const pending = await unauthenticatedNotes(midenClient, notes);
|
|
53
58
|
if (pending.length === 0) {
|
|
54
59
|
return;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
const proofs = new Map<string, NoteInclusionProof>();
|
|
58
63
|
try {
|
|
59
|
-
const rpcClient = new RpcClient(new Endpoint(
|
|
64
|
+
const rpcClient = new RpcClient(new Endpoint(midenRpcEndpoint));
|
|
60
65
|
const fetched = await retryRpcRead(
|
|
61
66
|
() => rpcClient.getNotesById(pending.map((note) => note.id())),
|
|
62
67
|
resolveRpcConfig(options.rpc),
|
|
@@ -81,7 +86,7 @@ export async function ensureNotesAuthenticated(
|
|
|
81
86
|
);
|
|
82
87
|
}
|
|
83
88
|
const { outcome, wasImported } = await importNoteWithProof(
|
|
84
|
-
|
|
89
|
+
midenClient,
|
|
85
90
|
'proposal',
|
|
86
91
|
idHex,
|
|
87
92
|
note,
|
|
@@ -99,10 +104,10 @@ export async function ensureNotesAuthenticated(
|
|
|
99
104
|
// height; a newer one lands unverified until a sync fetches its block
|
|
100
105
|
// header. A cosigner that just loaded the account is typically behind the
|
|
101
106
|
// note's block, so sync once and re-check before failing.
|
|
102
|
-
if ((await unauthenticatedNotes(
|
|
103
|
-
await
|
|
107
|
+
if ((await unauthenticatedNotes(midenClient, notes)).length > 0) {
|
|
108
|
+
await midenClient.syncChain();
|
|
104
109
|
}
|
|
105
|
-
const still = await unauthenticatedNotes(
|
|
110
|
+
const still = await unauthenticatedNotes(midenClient, notes);
|
|
106
111
|
if (still.length > 0) {
|
|
107
112
|
throw new ConsumeNoteNotAuthenticatedError(
|
|
108
113
|
noteIdHex(still[0]),
|
|
@@ -114,12 +119,12 @@ export async function ensureNotesAuthenticated(
|
|
|
114
119
|
|
|
115
120
|
/** The subset of `notes` whose local record is missing or carries no proof. */
|
|
116
121
|
async function unauthenticatedNotes(
|
|
117
|
-
|
|
122
|
+
midenClient: MidenClient,
|
|
118
123
|
notes: readonly Note[],
|
|
119
124
|
): Promise<Note[]> {
|
|
120
125
|
const pending: Note[] = [];
|
|
121
126
|
for (const note of notes) {
|
|
122
|
-
const record = await
|
|
127
|
+
const record = await midenClient.notes.get(noteIdHex(note));
|
|
123
128
|
if (!record || !record.isAuthenticated()) {
|
|
124
129
|
pending.push(note);
|
|
125
130
|
}
|
|
@@ -5,7 +5,6 @@ export interface SignatureOptions {
|
|
|
5
5
|
salt?: Word;
|
|
6
6
|
signatureAdviceMap?: AdviceMap;
|
|
7
7
|
signatureScheme?: SignatureScheme;
|
|
8
|
-
midenRpcEndpoint?: string;
|
|
9
8
|
/**
|
|
10
9
|
* The block the transaction summary binds. Omitted, the store's sync height,
|
|
11
10
|
* which is right for the party creating a proposal. A cosigner or executor
|
|
@@ -23,10 +22,6 @@ export interface SignatureOptions {
|
|
|
23
22
|
approvalExpirationDelta?: number;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
export interface MidenClientSignatureOptions extends SignatureOptions {
|
|
27
|
-
midenRpcEndpoint: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
25
|
/**
|
|
31
26
|
* Options for a request a multisig account executes. The account decides the
|
|
32
27
|
* auth args the request has to carry, so every multisig builder needs it.
|
|
@@ -34,7 +29,3 @@ export interface MidenClientSignatureOptions extends SignatureOptions {
|
|
|
34
29
|
export interface MultisigRequestOptions extends SignatureOptions {
|
|
35
30
|
accountId: string;
|
|
36
31
|
}
|
|
37
|
-
|
|
38
|
-
export interface MidenClientMultisigRequestOptions extends MultisigRequestOptions {
|
|
39
|
-
midenRpcEndpoint: string;
|
|
40
|
-
}
|
package/src/transaction/p2id.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TransactionRequest, Word } from '@miden-sdk/miden-sdk';
|
|
1
|
+
import type { MidenClient, TransactionRequest, Word } from '@miden-sdk/miden-sdk';
|
|
2
2
|
import {
|
|
3
3
|
AccountId,
|
|
4
4
|
Felt,
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
Poseidon2,
|
|
17
17
|
Word as WordType,
|
|
18
18
|
} from '@miden-sdk/miden-sdk';
|
|
19
|
-
import type { RawClientSource } from '../raw-client.js';
|
|
20
19
|
import { buildMultisigRequest, multisigRequestBuilder } from './authArgs.js';
|
|
21
20
|
import { normalizeHexWord } from '../utils/encoding.js';
|
|
22
21
|
import type { SignatureOptions } from './options.js';
|
|
@@ -163,7 +162,7 @@ export function buildP2idNoteFromMetadata(
|
|
|
163
162
|
}
|
|
164
163
|
|
|
165
164
|
export async function buildP2idTransactionRequest(
|
|
166
|
-
client:
|
|
165
|
+
client: MidenClient,
|
|
167
166
|
senderId: string,
|
|
168
167
|
recipientId: string,
|
|
169
168
|
faucetId: string,
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
TransactionRequest,
|
|
4
|
-
TransactionSummary,
|
|
5
|
-
WasmWebClient,
|
|
6
|
-
} from '@miden-sdk/miden-sdk';
|
|
7
|
-
import { AccountId, ChainAnchor, Word } from '@miden-sdk/miden-sdk';
|
|
1
|
+
import type { MidenClient, TransactionRequest, TransactionSummary } from '@miden-sdk/miden-sdk';
|
|
2
|
+
import { ChainAnchor, Word } from '@miden-sdk/miden-sdk';
|
|
8
3
|
import { BoundBlockNotDeclaredError } from '../multisig/authArgErrors.js';
|
|
9
|
-
import { getRawMidenClient } from '../raw-client.js';
|
|
10
4
|
import { base64ToUint8Array, normalizeHexWord, uint8ArrayToBase64 } from '../utils/encoding.js';
|
|
11
5
|
import { requestBoundBlockNum } from './authArgs.js';
|
|
12
6
|
|
|
@@ -85,29 +79,15 @@ export function isStaleChainError(error: unknown): boolean {
|
|
|
85
79
|
* at it. A proposer builds at the sync height the anchor is captured at, and
|
|
86
80
|
* the check below is what makes that hold.
|
|
87
81
|
*/
|
|
88
|
-
export function executeForSummary(
|
|
89
|
-
client: MidenClient,
|
|
90
|
-
accountId: string,
|
|
91
|
-
txRequest: TransactionRequest,
|
|
92
|
-
midenRpcEndpoint: string,
|
|
93
|
-
): Promise<{ summary: TransactionSummary; anchor: ChainAnchor }>;
|
|
94
|
-
export function executeForSummary(
|
|
95
|
-
client: WasmWebClient,
|
|
96
|
-
accountId: string,
|
|
97
|
-
txRequest: TransactionRequest,
|
|
98
|
-
midenRpcEndpoint?: string,
|
|
99
|
-
): Promise<{ summary: TransactionSummary; anchor: ChainAnchor }>;
|
|
100
82
|
export async function executeForSummary(
|
|
101
|
-
client: MidenClient
|
|
83
|
+
client: MidenClient,
|
|
102
84
|
accountId: string,
|
|
103
85
|
txRequest: TransactionRequest,
|
|
104
|
-
midenRpcEndpoint?: string,
|
|
105
86
|
): Promise<{ summary: TransactionSummary; anchor: ChainAnchor }> {
|
|
106
|
-
const
|
|
107
|
-
const anchor = await rawClient.chainAnchorForRequest(txRequest);
|
|
87
|
+
const anchor = await client.transactions.captureAnchor(txRequest);
|
|
108
88
|
let summary: TransactionSummary;
|
|
109
89
|
try {
|
|
110
|
-
summary = await executeForSummaryAtTip(
|
|
90
|
+
summary = await executeForSummaryAtTip(client, accountId, txRequest);
|
|
111
91
|
} catch (error) {
|
|
112
92
|
anchor.free();
|
|
113
93
|
throw error;
|
|
@@ -145,27 +125,17 @@ export async function executeForSummary(
|
|
|
145
125
|
* @throws BoundBlockNotDeclaredError when the request binds a block in its
|
|
146
126
|
* multisig auth args without declaring it.
|
|
147
127
|
*/
|
|
148
|
-
export function executeForSummaryAtTip(
|
|
149
|
-
client: MidenClient,
|
|
150
|
-
accountId: string,
|
|
151
|
-
txRequest: TransactionRequest,
|
|
152
|
-
midenRpcEndpoint: string,
|
|
153
|
-
): Promise<TransactionSummary>;
|
|
154
|
-
export function executeForSummaryAtTip(
|
|
155
|
-
client: WasmWebClient,
|
|
156
|
-
accountId: string,
|
|
157
|
-
txRequest: TransactionRequest,
|
|
158
|
-
midenRpcEndpoint?: string,
|
|
159
|
-
): Promise<TransactionSummary>;
|
|
160
128
|
export async function executeForSummaryAtTip(
|
|
161
|
-
client: MidenClient
|
|
129
|
+
client: MidenClient,
|
|
162
130
|
accountId: string,
|
|
163
131
|
txRequest: TransactionRequest,
|
|
164
|
-
midenRpcEndpoint?: string,
|
|
165
132
|
): Promise<TransactionSummary> {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
133
|
+
await prepareTipExecution(client, txRequest);
|
|
134
|
+
return client.transactions.preview({
|
|
135
|
+
operation: 'custom',
|
|
136
|
+
account: accountId,
|
|
137
|
+
request: txRequest,
|
|
138
|
+
});
|
|
169
139
|
}
|
|
170
140
|
|
|
171
141
|
/**
|
|
@@ -177,13 +147,13 @@ export async function executeForSummaryAtTip(
|
|
|
177
147
|
* multisig auth args without declaring it.
|
|
178
148
|
*/
|
|
179
149
|
export async function prepareTipExecution(
|
|
180
|
-
client:
|
|
150
|
+
client: MidenClient,
|
|
181
151
|
request: TransactionRequest,
|
|
182
|
-
|
|
152
|
+
syncChain?: () => Promise<unknown>,
|
|
183
153
|
): Promise<void> {
|
|
184
154
|
const boundBlockNum = requireDeclaredBoundBlock(request);
|
|
185
155
|
if (boundBlockNum !== undefined) {
|
|
186
|
-
await syncToBoundBlock(client, boundBlockNum,
|
|
156
|
+
await syncToBoundBlock(client, boundBlockNum, syncChain);
|
|
187
157
|
}
|
|
188
158
|
}
|
|
189
159
|
|
|
@@ -207,8 +177,8 @@ export function requireDeclaredBoundBlock(request: TransactionRequest): number |
|
|
|
207
177
|
* proposal binds. Execution at a tip below it fails with "requested block N is
|
|
208
178
|
* after transaction reference block M", and a store that has never synced (a
|
|
209
179
|
* cosigner that has only just loaded the account) holds no header to rebuild
|
|
210
|
-
* the request from. `
|
|
211
|
-
* policy.
|
|
180
|
+
* the request from. The sync is a chain sync; `syncChain` lets a caller wrap
|
|
181
|
+
* it in its own retry policy.
|
|
212
182
|
*
|
|
213
183
|
* This does not make a store that is already past the bound block current. An
|
|
214
184
|
* execution loads foreign accounts, the fee faucet among them, at the store's
|
|
@@ -218,14 +188,14 @@ export function requireDeclaredBoundBlock(request: TransactionRequest): number |
|
|
|
218
188
|
* @throws ChainBehindBoundBlockError when the node has not reached the block.
|
|
219
189
|
*/
|
|
220
190
|
export async function syncToBoundBlock(
|
|
221
|
-
client:
|
|
191
|
+
client: MidenClient,
|
|
222
192
|
blockNum: number,
|
|
223
|
-
|
|
193
|
+
syncChain: () => Promise<unknown> = () => client.syncChain(),
|
|
224
194
|
): Promise<void> {
|
|
225
195
|
if ((await client.getSyncHeight()) >= blockNum) {
|
|
226
196
|
return;
|
|
227
197
|
}
|
|
228
|
-
await
|
|
198
|
+
await syncChain();
|
|
229
199
|
const syncHeight = await client.getSyncHeight();
|
|
230
200
|
if (syncHeight < blockNum) {
|
|
231
201
|
throw new ChainBehindBoundBlockError({ syncHeight, boundBlockNum: blockNum });
|
|
@@ -241,30 +211,18 @@ export async function syncToBoundBlock(
|
|
|
241
211
|
* reproduced with {@link executeForSummaryAtTip}: re-executing it at an anchor
|
|
242
212
|
* fails once the node prunes the anchor block's account state.
|
|
243
213
|
*/
|
|
244
|
-
export function executeForSummaryAt(
|
|
245
|
-
client: MidenClient,
|
|
246
|
-
accountId: string,
|
|
247
|
-
txRequest: TransactionRequest,
|
|
248
|
-
anchor: ChainAnchor,
|
|
249
|
-
midenRpcEndpoint: string,
|
|
250
|
-
): Promise<TransactionSummary>;
|
|
251
|
-
export function executeForSummaryAt(
|
|
252
|
-
client: WasmWebClient,
|
|
253
|
-
accountId: string,
|
|
254
|
-
txRequest: TransactionRequest,
|
|
255
|
-
anchor: ChainAnchor,
|
|
256
|
-
midenRpcEndpoint?: string,
|
|
257
|
-
): Promise<TransactionSummary>;
|
|
258
214
|
export async function executeForSummaryAt(
|
|
259
|
-
client: MidenClient
|
|
215
|
+
client: MidenClient,
|
|
260
216
|
accountId: string,
|
|
261
217
|
txRequest: TransactionRequest,
|
|
262
218
|
anchor: ChainAnchor,
|
|
263
|
-
midenRpcEndpoint?: string,
|
|
264
219
|
): Promise<TransactionSummary> {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
220
|
+
return client.transactions.preview({
|
|
221
|
+
operation: 'custom',
|
|
222
|
+
account: accountId,
|
|
223
|
+
request: txRequest,
|
|
224
|
+
anchor,
|
|
225
|
+
});
|
|
268
226
|
}
|
|
269
227
|
|
|
270
228
|
/**
|
|
@@ -2,21 +2,18 @@ import {
|
|
|
2
2
|
type MidenClient,
|
|
3
3
|
TransactionRequest,
|
|
4
4
|
TransactionScript,
|
|
5
|
-
type WasmWebClient,
|
|
6
5
|
Word,
|
|
7
6
|
} from '@miden-sdk/miden-sdk';
|
|
8
|
-
import { compileTxScript } from '../raw-client.js';
|
|
9
7
|
import { normalizeHexWord } from '../utils/encoding.js';
|
|
10
8
|
import { authSchemeId } from '../utils/signature.js';
|
|
11
9
|
import { buildMultisigRequest, multisigRequestBuilder } from './authArgs.js';
|
|
12
|
-
import type {
|
|
10
|
+
import type { MultisigRequestOptions } from './options.js';
|
|
13
11
|
import type { SignatureScheme } from '../types.js';
|
|
14
12
|
|
|
15
13
|
async function buildUpdateGuardianScript(
|
|
16
|
-
client: MidenClient
|
|
14
|
+
client: MidenClient,
|
|
17
15
|
newGuardianPubkey: string,
|
|
18
16
|
signatureScheme: SignatureScheme,
|
|
19
|
-
midenRpcEndpoint?: string,
|
|
20
17
|
): Promise<TransactionScript> {
|
|
21
18
|
// A word literal preserves the key's element order on the operand stack.
|
|
22
19
|
const keyLiteral = normalizeHexWord(newGuardianPubkey);
|
|
@@ -36,31 +33,16 @@ pub proc main
|
|
|
36
33
|
end
|
|
37
34
|
`;
|
|
38
35
|
|
|
39
|
-
return
|
|
36
|
+
return client.compile.txScript({ code: scriptSource });
|
|
40
37
|
}
|
|
41
38
|
|
|
42
|
-
export function buildUpdateGuardianTransactionRequest(
|
|
43
|
-
client: MidenClient,
|
|
44
|
-
newGuardianPubkey: string,
|
|
45
|
-
options: MidenClientMultisigRequestOptions,
|
|
46
|
-
): Promise<{ request: TransactionRequest; salt: Word }>;
|
|
47
|
-
export function buildUpdateGuardianTransactionRequest(
|
|
48
|
-
client: WasmWebClient,
|
|
49
|
-
newGuardianPubkey: string,
|
|
50
|
-
options: MultisigRequestOptions,
|
|
51
|
-
): Promise<{ request: TransactionRequest; salt: Word }>;
|
|
52
39
|
export async function buildUpdateGuardianTransactionRequest(
|
|
53
|
-
client: MidenClient
|
|
40
|
+
client: MidenClient,
|
|
54
41
|
newGuardianPubkey: string,
|
|
55
42
|
options: MultisigRequestOptions,
|
|
56
43
|
): Promise<{ request: TransactionRequest; salt: Word }> {
|
|
57
44
|
const signatureScheme = options.signatureScheme ?? 'falcon';
|
|
58
|
-
const script = await buildUpdateGuardianScript(
|
|
59
|
-
client,
|
|
60
|
-
newGuardianPubkey,
|
|
61
|
-
signatureScheme,
|
|
62
|
-
options.midenRpcEndpoint,
|
|
63
|
-
);
|
|
45
|
+
const script = await buildUpdateGuardianScript(client, newGuardianPubkey, signatureScheme);
|
|
64
46
|
|
|
65
47
|
const { builder, saltHex } = await multisigRequestBuilder(client, options);
|
|
66
48
|
let txBuilder = builder.withCustomScript(script);
|