@openzeppelin/miden-multisig-client 0.12.7 → 0.13.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.
- package/README.md +42 -4
- package/dist/account/builder.d.ts +1 -1
- package/dist/account/builder.d.ts.map +1 -1
- package/dist/account/builder.js +7 -5
- package/dist/account/builder.js.map +1 -1
- package/dist/account/masm.d.ts +3 -3
- package/dist/account/masm.d.ts.map +1 -1
- package/dist/account/masm.js +101 -98
- package/dist/account/masm.js.map +1 -1
- package/dist/account/storage.d.ts +1 -1
- package/dist/account/storage.d.ts.map +1 -1
- package/dist/account/storage.js +17 -7
- package/dist/account/storage.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -2
- package/dist/client.js.map +1 -1
- package/dist/client.test.js +4 -4
- package/dist/client.test.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/inspector.d.ts +1 -1
- package/dist/inspector.d.ts.map +1 -1
- package/dist/inspector.js +16 -10
- package/dist/inspector.js.map +1 -1
- package/dist/inspector.test.js +33 -22
- package/dist/inspector.test.js.map +1 -1
- package/dist/multisig/helpers.d.ts +1 -1
- package/dist/multisig/helpers.d.ts.map +1 -1
- package/dist/multisig/helpers.js +1 -1
- package/dist/multisig/helpers.js.map +1 -1
- package/dist/multisig/helpers.test.js +2 -2
- package/dist/multisig/helpers.test.js.map +1 -1
- package/dist/multisig/proposal/execution.d.ts +18 -0
- package/dist/multisig/proposal/execution.d.ts.map +1 -0
- package/dist/multisig/proposal/execution.js +147 -0
- package/dist/multisig/proposal/execution.js.map +1 -0
- package/dist/multisig/proposal/parser.d.ts +17 -0
- package/dist/multisig/proposal/parser.d.ts.map +1 -0
- package/dist/multisig/proposal/parser.js +147 -0
- package/dist/multisig/proposal/parser.js.map +1 -0
- package/dist/multisig/signing.d.ts +5 -0
- package/dist/multisig/signing.d.ts.map +1 -0
- package/dist/multisig/signing.js +14 -0
- package/dist/multisig/signing.js.map +1 -0
- package/dist/multisig.d.ts +9 -13
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +109 -337
- package/dist/multisig.js.map +1 -1
- package/dist/multisig.test.js +8 -4
- package/dist/multisig.test.js.map +1 -1
- package/dist/signer.d.ts +2 -20
- package/dist/signer.d.ts.map +1 -1
- package/dist/signer.js +2 -82
- package/dist/signer.js.map +1 -1
- package/dist/signer.test.js +24 -24
- package/dist/signer.test.js.map +1 -1
- package/dist/signers/ecdsa.d.ts +12 -0
- package/dist/signers/ecdsa.d.ts.map +1 -0
- package/dist/signers/ecdsa.js +30 -0
- package/dist/signers/ecdsa.js.map +1 -0
- package/dist/signers/falcon.d.ts +12 -0
- package/dist/signers/falcon.d.ts.map +1 -0
- package/dist/signers/falcon.js +31 -0
- package/dist/signers/falcon.js.map +1 -0
- package/dist/signers/falcon.test.d.ts +2 -0
- package/dist/signers/falcon.test.d.ts.map +1 -0
- package/dist/signers/falcon.test.js +113 -0
- package/dist/signers/falcon.test.js.map +1 -0
- package/dist/signers/index.d.ts +5 -0
- package/dist/signers/index.d.ts.map +1 -0
- package/dist/signers/index.js +5 -0
- package/dist/signers/index.js.map +1 -0
- package/dist/signers/miden-wallet.d.ts +16 -0
- package/dist/signers/miden-wallet.d.ts.map +1 -0
- package/dist/signers/miden-wallet.js +35 -0
- package/dist/signers/miden-wallet.js.map +1 -0
- package/dist/signers/miden-wallet.test.d.ts +2 -0
- package/dist/signers/miden-wallet.test.d.ts.map +1 -0
- package/dist/signers/miden-wallet.test.js +107 -0
- package/dist/signers/miden-wallet.test.js.map +1 -0
- package/dist/signers/para.d.ts +21 -0
- package/dist/signers/para.d.ts.map +1 -0
- package/dist/signers/para.js +43 -0
- package/dist/signers/para.js.map +1 -0
- package/dist/signers/para.test.d.ts +2 -0
- package/dist/signers/para.test.d.ts.map +1 -0
- package/dist/signers/para.test.js +88 -0
- package/dist/signers/para.test.js.map +1 -0
- package/dist/transaction/consumeNotes.d.ts +3 -3
- package/dist/transaction/consumeNotes.d.ts.map +1 -1
- package/dist/transaction/consumeNotes.js +11 -7
- package/dist/transaction/consumeNotes.js.map +1 -1
- package/dist/transaction/options.d.ts +2 -2
- package/dist/transaction/options.d.ts.map +1 -1
- package/dist/transaction/p2id.d.ts +1 -1
- package/dist/transaction/p2id.d.ts.map +1 -1
- package/dist/transaction/p2id.js +5 -5
- package/dist/transaction/p2id.js.map +1 -1
- package/dist/transaction/summary.d.ts +1 -1
- package/dist/transaction/summary.d.ts.map +1 -1
- package/dist/transaction/summary.js +1 -1
- package/dist/transaction/summary.js.map +1 -1
- package/dist/transaction/updatePsm.d.ts +1 -1
- package/dist/transaction/updatePsm.d.ts.map +1 -1
- package/dist/transaction/updatePsm.js +5 -5
- package/dist/transaction/updatePsm.js.map +1 -1
- package/dist/transaction/updateSigners.d.ts +1 -1
- package/dist/transaction/updateSigners.d.ts.map +1 -1
- package/dist/transaction/updateSigners.js +5 -5
- package/dist/transaction/updateSigners.js.map +1 -1
- package/dist/transaction.test.js +1 -1
- package/dist/transaction.test.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/digest.d.ts +6 -0
- package/dist/utils/digest.d.ts.map +1 -0
- package/dist/utils/digest.js +22 -0
- package/dist/utils/digest.js.map +1 -0
- package/dist/utils/ecdsa.d.ts +8 -0
- package/dist/utils/ecdsa.d.ts.map +1 -0
- package/dist/utils/ecdsa.js +60 -0
- package/dist/utils/ecdsa.js.map +1 -0
- package/dist/utils/ecdsa.test.d.ts +2 -0
- package/dist/utils/ecdsa.test.d.ts.map +1 -0
- package/dist/utils/ecdsa.test.js +85 -0
- package/dist/utils/ecdsa.test.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/key.d.ts +10 -0
- package/dist/utils/key.d.ts.map +1 -0
- package/dist/utils/key.js +38 -0
- package/dist/utils/key.js.map +1 -0
- package/dist/utils/key.test.d.ts +2 -0
- package/dist/utils/key.test.d.ts.map +1 -0
- package/dist/utils/key.test.js +80 -0
- package/dist/utils/key.test.js.map +1 -0
- package/dist/utils/random.d.ts +1 -1
- package/dist/utils/random.d.ts.map +1 -1
- package/dist/utils/random.js +1 -1
- package/dist/utils/random.js.map +1 -1
- package/dist/utils/signature.d.ts +2 -1
- package/dist/utils/signature.d.ts.map +1 -1
- package/dist/utils/signature.js +6 -3
- package/dist/utils/signature.js.map +1 -1
- package/dist/utils/signature.test.js +11 -11
- package/dist/utils/signature.test.js.map +1 -1
- package/dist/utils/word.d.ts +6 -1
- package/dist/utils/word.d.ts.map +1 -1
- package/dist/utils/word.js +11 -0
- package/dist/utils/word.js.map +1 -1
- package/dist/utils/word.test.js +54 -3
- package/dist/utils/word.test.js.map +1 -1
- package/package.json +4 -5
- package/src/account/builder.ts +7 -5
- package/src/account/masm.ts +103 -99
- package/src/account/storage.ts +19 -7
- package/src/client.test.ts +4 -4
- package/src/client.ts +3 -3
- package/src/index.ts +8 -1
- package/src/inspector.test.ts +38 -25
- package/src/inspector.ts +18 -10
- package/src/multisig/helpers.test.ts +2 -2
- package/src/multisig/helpers.ts +2 -1
- package/src/multisig/proposal/execution.ts +320 -0
- package/src/multisig/proposal/parser.ts +191 -0
- package/src/multisig/signing.ts +24 -0
- package/src/multisig.test.ts +8 -4
- package/src/multisig.ts +153 -434
- package/src/signer.ts +2 -95
- package/src/signers/ecdsa.ts +35 -0
- package/src/{signer.test.ts → signers/falcon.test.ts} +29 -33
- package/src/signers/falcon.ts +36 -0
- package/src/signers/index.ts +4 -0
- package/src/signers/miden-wallet.test.ts +119 -0
- package/src/signers/miden-wallet.ts +49 -0
- package/src/signers/para.test.ts +103 -0
- package/src/signers/para.ts +60 -0
- package/src/transaction/consumeNotes.ts +14 -10
- package/src/transaction/options.ts +2 -2
- package/src/transaction/p2id.ts +3 -8
- package/src/transaction/summary.ts +2 -2
- package/src/transaction/updatePsm.ts +5 -6
- package/src/transaction/updateSigners.ts +5 -6
- package/src/transaction.test.ts +1 -1
- package/src/types.ts +1 -1
- package/src/utils/digest.ts +25 -0
- package/src/utils/ecdsa.test.ts +104 -0
- package/src/utils/ecdsa.ts +77 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/key.test.ts +89 -0
- package/src/utils/key.ts +49 -0
- package/src/utils/random.ts +1 -1
- package/src/utils/signature.test.ts +11 -11
- package/src/utils/signature.ts +10 -3
- package/src/utils/word.test.ts +57 -3
- package/src/utils/word.ts +13 -1
package/src/multisig.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PsmHttpClient, type
|
|
1
|
+
import { PsmHttpClient, type Signer, type AuthConfig, type StateObject } from '@openzeppelin/psm-client';
|
|
2
2
|
import type {
|
|
3
3
|
ConsumableNote,
|
|
4
4
|
ExportedTransactionProposal,
|
|
@@ -6,7 +6,6 @@ import type {
|
|
|
6
6
|
NoteAsset,
|
|
7
7
|
TransactionProposal,
|
|
8
8
|
ProposalMetadata,
|
|
9
|
-
TransactionProposalSignature,
|
|
10
9
|
TransactionProposalStatus,
|
|
11
10
|
ProposalType,
|
|
12
11
|
SignTransactionProposalParams,
|
|
@@ -15,16 +14,11 @@ import type {
|
|
|
15
14
|
} from './types.js';
|
|
16
15
|
import type { ProcedureName } from './procedures.js';
|
|
17
16
|
import { AccountInspector, type DetectedMultisigConfig } from './inspector.js';
|
|
18
|
-
import type { WebClient, TransactionRequest } from '@
|
|
17
|
+
import type { WebClient, TransactionRequest } from '@miden-sdk/miden-sdk';
|
|
19
18
|
import {
|
|
20
19
|
Account,
|
|
21
20
|
AccountId,
|
|
22
|
-
|
|
23
|
-
FeltArray,
|
|
24
|
-
Signature,
|
|
25
|
-
TransactionSummary,
|
|
26
|
-
Word,
|
|
27
|
-
} from '@demox-labs/miden-sdk';
|
|
21
|
+
} from '@miden-sdk/miden-sdk';
|
|
28
22
|
import {
|
|
29
23
|
executeForSummary,
|
|
30
24
|
buildUpdateSignersTransactionRequest,
|
|
@@ -37,8 +31,19 @@ import {
|
|
|
37
31
|
uint8ArrayToBase64,
|
|
38
32
|
normalizeHexWord,
|
|
39
33
|
} from './utils/encoding.js';
|
|
40
|
-
import {
|
|
34
|
+
import { signatureHexToBytes } from './utils/signature.js';
|
|
41
35
|
import { computeCommitmentFromTxSummary, accountIdToHex } from './multisig/helpers.js';
|
|
36
|
+
import {
|
|
37
|
+
buildPsmMetadata,
|
|
38
|
+
deltaToProposal,
|
|
39
|
+
resolveMetadata,
|
|
40
|
+
signatureRequirementForProposal,
|
|
41
|
+
} from './multisig/proposal/parser.js';
|
|
42
|
+
import {
|
|
43
|
+
toPsmSignature,
|
|
44
|
+
buildPsmSignatureFromSigner,
|
|
45
|
+
} from './multisig/signing.js';
|
|
46
|
+
import { executeProposalWorkflow } from './multisig/proposal/execution.js';
|
|
42
47
|
|
|
43
48
|
export interface AccountState {
|
|
44
49
|
accountId: string;
|
|
@@ -50,12 +55,12 @@ export interface AccountState {
|
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
export class Multisig {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
account: Account | null;
|
|
59
|
+
threshold: number;
|
|
60
|
+
signerCommitments: string[];
|
|
61
|
+
psmCommitment: string;
|
|
57
62
|
psmPublicKey?: string;
|
|
58
|
-
|
|
63
|
+
procedureThresholds: Map<ProcedureName, number>;
|
|
59
64
|
readonly signatureScheme: Signer['scheme'];
|
|
60
65
|
|
|
61
66
|
private psm: PsmHttpClient;
|
|
@@ -203,8 +208,7 @@ export class Multisig {
|
|
|
203
208
|
const server = normalizeHexWord(response.ackCommitment);
|
|
204
209
|
if (onChain !== server) {
|
|
205
210
|
throw new Error(
|
|
206
|
-
`PSM commitment mismatch: on-chain=${onChain}, server=${server}
|
|
207
|
-
`Re-create the account with getPubkey('${this.signatureScheme}') to get the correct PSM commitment.`
|
|
211
|
+
`PSM commitment mismatch: on-chain=${onChain}, server=${server}`
|
|
208
212
|
);
|
|
209
213
|
}
|
|
210
214
|
}
|
|
@@ -215,6 +219,14 @@ export class Multisig {
|
|
|
215
219
|
const state = await this.syncState();
|
|
216
220
|
const notes = await this.getConsumableNotes();
|
|
217
221
|
const config = AccountInspector.fromBase64(state.stateDataBase64, this.signatureScheme);
|
|
222
|
+
|
|
223
|
+
this.threshold = config.threshold;
|
|
224
|
+
this.signerCommitments = config.signerCommitments;
|
|
225
|
+
if (config.psmCommitment) {
|
|
226
|
+
this.psmCommitment = config.psmCommitment;
|
|
227
|
+
}
|
|
228
|
+
this.procedureThresholds = config.procedureThresholds;
|
|
229
|
+
|
|
218
230
|
return { proposals, state, notes, config };
|
|
219
231
|
}
|
|
220
232
|
|
|
@@ -224,9 +236,44 @@ export class Multisig {
|
|
|
224
236
|
}
|
|
225
237
|
|
|
226
238
|
async switchPsm(psmClient: PsmHttpClient): Promise<void> {
|
|
239
|
+
const accountId = AccountId.fromHex(this._accountId);
|
|
240
|
+
const localAccount = await this.webClient.getAccount(accountId);
|
|
241
|
+
if (localAccount) {
|
|
242
|
+
this.account = localAccount;
|
|
243
|
+
const config = AccountInspector.fromAccount(localAccount, this.signatureScheme);
|
|
244
|
+
if (config.psmCommitment) {
|
|
245
|
+
this.psmCommitment = config.psmCommitment;
|
|
246
|
+
}
|
|
247
|
+
this.threshold = config.threshold;
|
|
248
|
+
this.signerCommitments = config.signerCommitments;
|
|
249
|
+
this.procedureThresholds = config.procedureThresholds;
|
|
250
|
+
}
|
|
251
|
+
|
|
227
252
|
this.setPsmClient(psmClient);
|
|
228
|
-
|
|
229
|
-
|
|
253
|
+
|
|
254
|
+
const accountBytes: Uint8Array = this.account!.serialize();
|
|
255
|
+
const stateData = uint8ArrayToBase64(accountBytes);
|
|
256
|
+
|
|
257
|
+
const auth: AuthConfig = this.signer.scheme === 'ecdsa'
|
|
258
|
+
? { MidenEcdsa: { cosigner_commitments: this.signerCommitments } }
|
|
259
|
+
: { MidenFalconRpo: { cosigner_commitments: this.signerCommitments } };
|
|
260
|
+
|
|
261
|
+
const response = await this.psm.configure({
|
|
262
|
+
accountId: this._accountId,
|
|
263
|
+
auth,
|
|
264
|
+
initialState: { data: stateData, accountId: this._accountId },
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
if (!response.success) {
|
|
268
|
+
throw new Error(`Failed to register on PSM: ${response.message}`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (response.ackCommitment) {
|
|
272
|
+
this.psmCommitment = normalizeHexWord(response.ackCommitment);
|
|
273
|
+
}
|
|
274
|
+
if (response.ackPubkey) {
|
|
275
|
+
this.psmPublicKey = response.ackPubkey;
|
|
276
|
+
}
|
|
230
277
|
}
|
|
231
278
|
|
|
232
279
|
async syncTransactionProposals(): Promise<TransactionProposal[]> {
|
|
@@ -238,16 +285,22 @@ export class Multisig {
|
|
|
238
285
|
serverProposalIds.add(proposalId);
|
|
239
286
|
const existingProposal = this.proposals.get(proposalId);
|
|
240
287
|
|
|
241
|
-
const resolvedMetadata =
|
|
242
|
-
existingProposal?.metadata ??
|
|
243
|
-
(delta.deltaPayload.metadata
|
|
244
|
-
? this.fromPsmMetadata(delta.deltaPayload.metadata)
|
|
245
|
-
: undefined);
|
|
288
|
+
const resolvedMetadata = resolveMetadata(delta, existingProposal?.metadata);
|
|
246
289
|
if (!resolvedMetadata) {
|
|
247
290
|
throw new Error('Missing proposal metadata from PSM');
|
|
248
291
|
}
|
|
249
292
|
|
|
250
|
-
const proposal =
|
|
293
|
+
const proposal = deltaToProposal({
|
|
294
|
+
delta,
|
|
295
|
+
proposalId,
|
|
296
|
+
metadata: resolvedMetadata,
|
|
297
|
+
signaturesRequired: signatureRequirementForProposal(
|
|
298
|
+
resolvedMetadata,
|
|
299
|
+
this.threshold,
|
|
300
|
+
(proposalType) => this.getEffectiveThreshold(proposalType),
|
|
301
|
+
),
|
|
302
|
+
existingSignatures: existingProposal?.signatures,
|
|
303
|
+
});
|
|
251
304
|
|
|
252
305
|
this.proposals.set(proposal.id, proposal);
|
|
253
306
|
}
|
|
@@ -268,7 +321,7 @@ export class Multisig {
|
|
|
268
321
|
}
|
|
269
322
|
|
|
270
323
|
async createProposal(nonce: number, txSummaryBase64: string, metadata: ProposalMetadata): Promise<TransactionProposal> {
|
|
271
|
-
const psmMetadata =
|
|
324
|
+
const psmMetadata = buildPsmMetadata(metadata);
|
|
272
325
|
|
|
273
326
|
const response = await this.psm.pushDeltaProposal({
|
|
274
327
|
accountId: this._accountId,
|
|
@@ -280,7 +333,16 @@ export class Multisig {
|
|
|
280
333
|
},
|
|
281
334
|
});
|
|
282
335
|
|
|
283
|
-
const proposal =
|
|
336
|
+
const proposal = deltaToProposal({
|
|
337
|
+
delta: response.delta,
|
|
338
|
+
proposalId: response.commitment,
|
|
339
|
+
metadata,
|
|
340
|
+
signaturesRequired: signatureRequirementForProposal(
|
|
341
|
+
metadata,
|
|
342
|
+
this.threshold,
|
|
343
|
+
(proposalType) => this.getEffectiveThreshold(proposalType),
|
|
344
|
+
),
|
|
345
|
+
});
|
|
284
346
|
this.proposals.set(proposal.id, proposal);
|
|
285
347
|
|
|
286
348
|
return proposal;
|
|
@@ -300,10 +362,6 @@ export class Multisig {
|
|
|
300
362
|
{ signatureScheme: this.signatureScheme }
|
|
301
363
|
);
|
|
302
364
|
|
|
303
|
-
const summary = await executeForSummary(this.webClient, this._accountId, request);
|
|
304
|
-
const summaryBase64 = uint8ArrayToBase64(summary.serialize());
|
|
305
|
-
const proposalNonce = options?.nonce ?? Date.now();
|
|
306
|
-
|
|
307
365
|
const metadata: ProposalMetadata = {
|
|
308
366
|
proposalType: 'add_signer',
|
|
309
367
|
targetThreshold,
|
|
@@ -311,9 +369,7 @@ export class Multisig {
|
|
|
311
369
|
saltHex: salt.toHex(),
|
|
312
370
|
description: `Add signer ${newCommitment.slice(0, 10)}...`,
|
|
313
371
|
};
|
|
314
|
-
|
|
315
|
-
const proposal = await this.createProposal(proposalNonce, summaryBase64, metadata);
|
|
316
|
-
return this.syncAfterCreate(proposal);
|
|
372
|
+
return this.createAndSyncFromRequest(request, metadata, options?.nonce);
|
|
317
373
|
}
|
|
318
374
|
|
|
319
375
|
async createRemoveSignerProposal(
|
|
@@ -351,10 +407,6 @@ export class Multisig {
|
|
|
351
407
|
{ signatureScheme: this.signatureScheme }
|
|
352
408
|
);
|
|
353
409
|
|
|
354
|
-
const summary = await executeForSummary(this.webClient, this._accountId, request);
|
|
355
|
-
const summaryBase64 = uint8ArrayToBase64(summary.serialize());
|
|
356
|
-
const proposalNonce = options?.nonce ?? Date.now();
|
|
357
|
-
|
|
358
410
|
const metadata: ProposalMetadata = {
|
|
359
411
|
proposalType: 'remove_signer',
|
|
360
412
|
targetThreshold,
|
|
@@ -362,9 +414,7 @@ export class Multisig {
|
|
|
362
414
|
saltHex: salt.toHex(),
|
|
363
415
|
description: `Remove signer ${signerToRemove.slice(0, 10)}...`,
|
|
364
416
|
};
|
|
365
|
-
|
|
366
|
-
const proposal = await this.createProposal(proposalNonce, summaryBase64, metadata);
|
|
367
|
-
return this.syncAfterCreate(proposal);
|
|
417
|
+
return this.createAndSyncFromRequest(request, metadata, options?.nonce);
|
|
368
418
|
}
|
|
369
419
|
|
|
370
420
|
async createChangeThresholdProposal(
|
|
@@ -388,10 +438,6 @@ export class Multisig {
|
|
|
388
438
|
{ signatureScheme: this.signatureScheme }
|
|
389
439
|
);
|
|
390
440
|
|
|
391
|
-
const summary = await executeForSummary(this.webClient, this._accountId, request);
|
|
392
|
-
const summaryBase64 = uint8ArrayToBase64(summary.serialize());
|
|
393
|
-
const proposalNonce = options?.nonce ?? Date.now();
|
|
394
|
-
|
|
395
441
|
const metadata: ProposalMetadata = {
|
|
396
442
|
proposalType: 'change_threshold',
|
|
397
443
|
targetThreshold: newThreshold,
|
|
@@ -399,9 +445,7 @@ export class Multisig {
|
|
|
399
445
|
saltHex: salt.toHex(),
|
|
400
446
|
description: `Change threshold from ${this.threshold} to ${newThreshold}`,
|
|
401
447
|
};
|
|
402
|
-
|
|
403
|
-
const proposal = await this.createProposal(proposalNonce, summaryBase64, metadata);
|
|
404
|
-
return this.syncAfterCreate(proposal);
|
|
448
|
+
return this.createAndSyncFromRequest(request, metadata, options?.nonce);
|
|
405
449
|
}
|
|
406
450
|
|
|
407
451
|
async createSwitchPsmProposal(
|
|
@@ -452,11 +496,7 @@ export class Multisig {
|
|
|
452
496
|
throw new Error('At least one note ID is required');
|
|
453
497
|
}
|
|
454
498
|
|
|
455
|
-
const { request, salt } = buildConsumeNotesTransactionRequest(noteIds);
|
|
456
|
-
|
|
457
|
-
const summary = await executeForSummary(this.webClient, this._accountId, request);
|
|
458
|
-
const summaryBase64 = uint8ArrayToBase64(summary.serialize());
|
|
459
|
-
const proposalNonce = options?.nonce ?? Date.now();
|
|
499
|
+
const { request, salt } = await buildConsumeNotesTransactionRequest(this.webClient, noteIds);
|
|
460
500
|
|
|
461
501
|
const metadata: ProposalMetadata = {
|
|
462
502
|
proposalType: 'consume_notes',
|
|
@@ -464,9 +504,7 @@ export class Multisig {
|
|
|
464
504
|
saltHex: salt.toHex(),
|
|
465
505
|
description: `Consume ${noteIds.length} note(s)`,
|
|
466
506
|
};
|
|
467
|
-
|
|
468
|
-
const proposal = await this.createProposal(proposalNonce, summaryBase64, metadata);
|
|
469
|
-
return this.syncAfterCreate(proposal);
|
|
507
|
+
return this.createAndSyncFromRequest(request, metadata, options?.nonce);
|
|
470
508
|
}
|
|
471
509
|
|
|
472
510
|
async createSendProposal(
|
|
@@ -486,10 +524,6 @@ export class Multisig {
|
|
|
486
524
|
amount,
|
|
487
525
|
);
|
|
488
526
|
|
|
489
|
-
const summary = await executeForSummary(this.webClient, this._accountId, request);
|
|
490
|
-
const summaryBase64 = uint8ArrayToBase64(summary.serialize());
|
|
491
|
-
const proposalNonce = options?.nonce ?? Date.now();
|
|
492
|
-
|
|
493
527
|
const metadata: ProposalMetadata = {
|
|
494
528
|
proposalType: 'p2id',
|
|
495
529
|
saltHex: salt.toHex(),
|
|
@@ -498,9 +532,7 @@ export class Multisig {
|
|
|
498
532
|
amount: amount.toString(),
|
|
499
533
|
description: `Send ${amount} to ${recipientId.slice(0, 10)}...`,
|
|
500
534
|
};
|
|
501
|
-
|
|
502
|
-
const proposal = await this.createProposal(proposalNonce, summaryBase64, metadata);
|
|
503
|
-
return this.syncAfterCreate(proposal);
|
|
535
|
+
return this.createAndSyncFromRequest(request, metadata, options?.nonce);
|
|
504
536
|
}
|
|
505
537
|
|
|
506
538
|
async getConsumableNotes(): Promise<ConsumableNote[]> {
|
|
@@ -514,7 +546,7 @@ export class Multisig {
|
|
|
514
546
|
|
|
515
547
|
const canConsumeNow = consumability.some(
|
|
516
548
|
(c) => c.accountId().toString().toLowerCase() === this._accountId.toLowerCase() &&
|
|
517
|
-
c.consumableAfterBlock() === undefined
|
|
549
|
+
c.consumptionStatus().consumableAfterBlock() === undefined
|
|
518
550
|
);
|
|
519
551
|
|
|
520
552
|
if (canConsumeNow) {
|
|
@@ -539,12 +571,7 @@ export class Multisig {
|
|
|
539
571
|
|
|
540
572
|
async signTransactionProposal(commitment: string): Promise<TransactionProposal[]> {
|
|
541
573
|
const existingProposal = this.proposals.get(commitment);
|
|
542
|
-
|
|
543
|
-
const signatureHex = this.signer.signCommitment(commitment);
|
|
544
|
-
|
|
545
|
-
const signature: ProposalSignature = this.signer.scheme === 'ecdsa'
|
|
546
|
-
? { scheme: 'ecdsa', signature: signatureHex, publicKey: this.signer.publicKey }
|
|
547
|
-
: { scheme: 'falcon', signature: signatureHex };
|
|
574
|
+
const signature = await buildPsmSignatureFromSigner(this.signer, commitment);
|
|
548
575
|
|
|
549
576
|
const delta = await this.psm.signDeltaProposal({
|
|
550
577
|
accountId: this._accountId,
|
|
@@ -552,15 +579,25 @@ export class Multisig {
|
|
|
552
579
|
signature,
|
|
553
580
|
});
|
|
554
581
|
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
proposal.metadata = existingProposal.metadata;
|
|
582
|
+
const resolvedMetadata = resolveMetadata(delta, existingProposal?.metadata);
|
|
583
|
+
if (!resolvedMetadata) {
|
|
584
|
+
throw new Error('Missing proposal metadata');
|
|
559
585
|
}
|
|
586
|
+
const proposal = deltaToProposal({
|
|
587
|
+
delta,
|
|
588
|
+
proposalId: commitment,
|
|
589
|
+
metadata: resolvedMetadata,
|
|
590
|
+
signaturesRequired: signatureRequirementForProposal(
|
|
591
|
+
resolvedMetadata,
|
|
592
|
+
this.threshold,
|
|
593
|
+
(proposalType) => this.getEffectiveThreshold(proposalType),
|
|
594
|
+
),
|
|
595
|
+
existingSignatures: existingProposal?.signatures,
|
|
596
|
+
});
|
|
560
597
|
|
|
561
598
|
this.proposals.set(proposal.id, proposal);
|
|
562
599
|
|
|
563
|
-
return this.
|
|
600
|
+
return this.listTransactionProposals();
|
|
564
601
|
}
|
|
565
602
|
|
|
566
603
|
async signTransactionProposalExternal(
|
|
@@ -570,10 +607,7 @@ export class Multisig {
|
|
|
570
607
|
const resolvedScheme = scheme ?? this.signatureScheme;
|
|
571
608
|
|
|
572
609
|
const existingProposal = this.proposals.get(commitment);
|
|
573
|
-
|
|
574
|
-
const signature: ProposalSignature = resolvedScheme === 'ecdsa'
|
|
575
|
-
? { scheme: 'ecdsa', signature: signatureHex, publicKey: publicKey! }
|
|
576
|
-
: { scheme: 'falcon', signature: signatureHex };
|
|
610
|
+
const signature = toPsmSignature(resolvedScheme, signatureHex, publicKey);
|
|
577
611
|
|
|
578
612
|
const delta = await this.psm.signDeltaProposal({
|
|
579
613
|
accountId: this._accountId,
|
|
@@ -581,15 +615,25 @@ export class Multisig {
|
|
|
581
615
|
signature,
|
|
582
616
|
});
|
|
583
617
|
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
proposal.metadata = existingProposal.metadata;
|
|
618
|
+
const resolvedMetadata = resolveMetadata(delta, existingProposal?.metadata);
|
|
619
|
+
if (!resolvedMetadata) {
|
|
620
|
+
throw new Error('Missing proposal metadata');
|
|
588
621
|
}
|
|
622
|
+
const proposal = deltaToProposal({
|
|
623
|
+
delta,
|
|
624
|
+
proposalId: commitment,
|
|
625
|
+
metadata: resolvedMetadata,
|
|
626
|
+
signaturesRequired: signatureRequirementForProposal(
|
|
627
|
+
resolvedMetadata,
|
|
628
|
+
this.threshold,
|
|
629
|
+
(proposalType) => this.getEffectiveThreshold(proposalType),
|
|
630
|
+
),
|
|
631
|
+
existingSignatures: existingProposal?.signatures,
|
|
632
|
+
});
|
|
589
633
|
|
|
590
634
|
this.proposals.set(proposal.id, proposal);
|
|
591
635
|
|
|
592
|
-
return this.
|
|
636
|
+
return this.listTransactionProposals();
|
|
593
637
|
}
|
|
594
638
|
|
|
595
639
|
async executeTransactionProposal(commitment: string): Promise<void> {
|
|
@@ -598,185 +642,18 @@ export class Multisig {
|
|
|
598
642
|
throw new Error(`Proposal not found: ${commitment}`);
|
|
599
643
|
}
|
|
600
644
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
: this.threshold
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
let delta: DeltaObject | undefined;
|
|
614
|
-
|
|
615
|
-
if (isSwitchPsm) {
|
|
616
|
-
txSummaryBase64 = proposal.txSummary;
|
|
617
|
-
} else {
|
|
618
|
-
const deltas = await this.psm.getDeltaProposals(this._accountId);
|
|
619
|
-
delta = deltas.find(
|
|
620
|
-
(d) => computeCommitmentFromTxSummary(d.deltaPayload.txSummary.data) === commitment
|
|
621
|
-
);
|
|
622
|
-
|
|
623
|
-
if (!delta) {
|
|
624
|
-
throw new Error(`Proposal not found on server: ${commitment}`);
|
|
625
|
-
}
|
|
626
|
-
txSummaryBase64 = delta.deltaPayload.txSummary.data;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
const txSummaryBytes = base64ToUint8Array(txSummaryBase64);
|
|
630
|
-
const txSummary = TransactionSummary.deserialize(txSummaryBytes);
|
|
631
|
-
const saltHex = txSummary.salt().toHex();
|
|
632
|
-
const txCommitmentHex = txSummary.toCommitment().toHex();
|
|
633
|
-
|
|
634
|
-
const adviceMap = new AdviceMap();
|
|
635
|
-
const normalizedSignerCommitments = new Set(
|
|
636
|
-
this.signerCommitments.map((c) => normalizeHexWord(c))
|
|
637
|
-
);
|
|
638
|
-
|
|
639
|
-
for (const cosignerSig of proposal.signatures) {
|
|
640
|
-
let signerCommitmentHex = normalizeHexWord(cosignerSig.signerId);
|
|
641
|
-
if (cosignerSig.signature.scheme === 'ecdsa' && cosignerSig.signature.publicKey) {
|
|
642
|
-
const derived = tryComputeEcdsaCommitmentHex(cosignerSig.signature.publicKey);
|
|
643
|
-
if (derived && derived !== signerCommitmentHex) {
|
|
644
|
-
if (!normalizedSignerCommitments.has(derived)) {
|
|
645
|
-
throw new Error(
|
|
646
|
-
`ECDSA public key commitment mismatch: derived commitment ${derived} is not in signerCommitments.`
|
|
647
|
-
);
|
|
648
|
-
}
|
|
649
|
-
signerCommitmentHex = derived;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
const signerCommitment = Word.fromHex(signerCommitmentHex);
|
|
653
|
-
const sigBytes = signatureHexToBytes(
|
|
654
|
-
cosignerSig.signature.signature,
|
|
655
|
-
cosignerSig.signature.scheme
|
|
656
|
-
);
|
|
657
|
-
const signature = Signature.deserialize(sigBytes);
|
|
658
|
-
const txCommitment = Word.fromHex(normalizeHexWord(txCommitmentHex));
|
|
659
|
-
|
|
660
|
-
const isEcdsa = cosignerSig.signature.scheme === 'ecdsa' && cosignerSig.signature.publicKey;
|
|
661
|
-
const { key, values } = buildSignatureAdviceEntry(
|
|
662
|
-
signerCommitment,
|
|
663
|
-
txCommitment,
|
|
664
|
-
signature,
|
|
665
|
-
isEcdsa ? cosignerSig.signature.publicKey : undefined,
|
|
666
|
-
isEcdsa ? cosignerSig.signature.signature : undefined,
|
|
667
|
-
);
|
|
668
|
-
adviceMap.insert(key, new FeltArray(values));
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
if (!isSwitchPsm && delta) {
|
|
672
|
-
const executionDelta = {
|
|
673
|
-
...delta,
|
|
674
|
-
deltaPayload: delta.deltaPayload.txSummary,
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
const pushResult = await this.psm.pushDelta(executionDelta);
|
|
678
|
-
const ackSigHex = pushResult.ackSig;
|
|
679
|
-
if (!ackSigHex) {
|
|
680
|
-
throw new Error('PSM did not return acknowledgment signature');
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const psmAckScheme: 'ecdsa' | 'falcon' = (pushResult.ackScheme as 'ecdsa' | 'falcon') || this.signatureScheme;
|
|
684
|
-
const psmAckPubkey = pushResult.ackPubkey || this.psmPublicKey;
|
|
685
|
-
const psmCommitmentHex = normalizeHexWord(this.psmCommitment);
|
|
686
|
-
|
|
687
|
-
if (psmAckScheme === 'ecdsa' && psmAckPubkey) {
|
|
688
|
-
const derived = tryComputeEcdsaCommitmentHex(psmAckPubkey);
|
|
689
|
-
if (derived && derived !== psmCommitmentHex) {
|
|
690
|
-
throw new Error(`PSM public key commitment mismatch`);
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
const psmCommitment = Word.fromHex(psmCommitmentHex);
|
|
694
|
-
const ackSigBytes = signatureHexToBytes(ackSigHex, psmAckScheme);
|
|
695
|
-
const ackSignature = Signature.deserialize(ackSigBytes);
|
|
696
|
-
const txCommitmentForAck = Word.fromHex(normalizeHexWord(txCommitmentHex));
|
|
697
|
-
const isAckEcdsa = psmAckScheme === 'ecdsa' && psmAckPubkey;
|
|
698
|
-
const { key: ackKey, values: ackValues } = buildSignatureAdviceEntry(
|
|
699
|
-
psmCommitment,
|
|
700
|
-
txCommitmentForAck,
|
|
701
|
-
ackSignature,
|
|
702
|
-
isAckEcdsa ? psmAckPubkey : undefined,
|
|
703
|
-
isAckEcdsa ? ackSigHex : undefined,
|
|
704
|
-
);
|
|
705
|
-
adviceMap.insert(ackKey, new FeltArray(ackValues));
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
const metadata = proposal.metadata;
|
|
709
|
-
if (!metadata) {
|
|
710
|
-
throw new Error('Proposal missing metadata');
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
let finalRequest: TransactionRequest;
|
|
714
|
-
switch (metadata.proposalType) {
|
|
715
|
-
case 'consume_notes': {
|
|
716
|
-
if (!metadata.noteIds || metadata.noteIds.length === 0) {
|
|
717
|
-
throw new Error('Proposal missing noteIds. Was it created with createConsumeNotesProposal?');
|
|
718
|
-
}
|
|
719
|
-
const { request } = buildConsumeNotesTransactionRequest(
|
|
720
|
-
metadata.noteIds,
|
|
721
|
-
{ salt: Word.fromHex(normalizeHexWord(saltHex)), signatureAdviceMap: adviceMap },
|
|
722
|
-
);
|
|
723
|
-
finalRequest = request;
|
|
724
|
-
break;
|
|
725
|
-
}
|
|
726
|
-
case 'switch_psm': {
|
|
727
|
-
if (!metadata.newPsmPubkey) {
|
|
728
|
-
throw new Error('Proposal missing newPsmPubkey. Was it created with createSwitchPsmProposal?');
|
|
729
|
-
}
|
|
730
|
-
const { request } = await buildUpdatePsmTransactionRequest(
|
|
731
|
-
this.webClient,
|
|
732
|
-
metadata.newPsmPubkey,
|
|
733
|
-
{
|
|
734
|
-
salt: Word.fromHex(normalizeHexWord(saltHex)),
|
|
735
|
-
signatureAdviceMap: adviceMap,
|
|
736
|
-
signatureScheme: this.signatureScheme,
|
|
737
|
-
},
|
|
738
|
-
);
|
|
739
|
-
finalRequest = request;
|
|
740
|
-
break;
|
|
741
|
-
}
|
|
742
|
-
case 'p2id': {
|
|
743
|
-
if (!metadata.recipientId || !metadata.faucetId || !metadata.amount) {
|
|
744
|
-
throw new Error('Proposal missing P2ID metadata (recipientId, faucetId, amount). Was it created with createP2idProposal?');
|
|
745
|
-
}
|
|
746
|
-
const { request } = buildP2idTransactionRequest(
|
|
747
|
-
this._accountId,
|
|
748
|
-
metadata.recipientId,
|
|
749
|
-
metadata.faucetId,
|
|
750
|
-
BigInt(metadata.amount),
|
|
751
|
-
{ salt: Word.fromHex(normalizeHexWord(saltHex)), signatureAdviceMap: adviceMap },
|
|
752
|
-
);
|
|
753
|
-
finalRequest = request;
|
|
754
|
-
break;
|
|
755
|
-
}
|
|
756
|
-
case 'unknown': {
|
|
757
|
-
throw new Error('Cannot execute proposal with unknown type. The proposal must have been imported without proper metadata.');
|
|
758
|
-
}
|
|
759
|
-
default: {
|
|
760
|
-
const { request } = await buildUpdateSignersTransactionRequest(
|
|
761
|
-
this.webClient,
|
|
762
|
-
metadata.targetThreshold,
|
|
763
|
-
metadata.targetSignerCommitments,
|
|
764
|
-
{
|
|
765
|
-
salt: Word.fromHex(normalizeHexWord(saltHex)),
|
|
766
|
-
signatureAdviceMap: adviceMap,
|
|
767
|
-
signatureScheme: this.signatureScheme,
|
|
768
|
-
},
|
|
769
|
-
);
|
|
770
|
-
finalRequest = request;
|
|
771
|
-
break;
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
const accountId = AccountId.fromHex(this._accountId);
|
|
776
|
-
const result = await this.webClient.executeTransaction(accountId, finalRequest);
|
|
777
|
-
const proven = await this.webClient.proveTransaction(result, null);
|
|
778
|
-
const submissionHeight = await this.webClient.submitProvenTransaction(proven, result);
|
|
779
|
-
await this.webClient.applyTransaction(result, submissionHeight);
|
|
645
|
+
await executeProposalWorkflow({
|
|
646
|
+
proposal,
|
|
647
|
+
accountId: this._accountId,
|
|
648
|
+
threshold: this.threshold,
|
|
649
|
+
signerCommitments: this.signerCommitments,
|
|
650
|
+
psmCommitment: this.psmCommitment,
|
|
651
|
+
psmPublicKey: this.psmPublicKey,
|
|
652
|
+
signatureScheme: this.signatureScheme,
|
|
653
|
+
getEffectiveThreshold: (proposalType) => this.getEffectiveThreshold(proposalType),
|
|
654
|
+
psm: this.psm,
|
|
655
|
+
webClient: this.webClient,
|
|
656
|
+
});
|
|
780
657
|
|
|
781
658
|
proposal.status = { type: 'finalized' };
|
|
782
659
|
}
|
|
@@ -855,7 +732,7 @@ export class Multisig {
|
|
|
855
732
|
return { proposal, proposals };
|
|
856
733
|
}
|
|
857
734
|
|
|
858
|
-
signTransactionProposalOffline(commitment: string): string {
|
|
735
|
+
async signTransactionProposalOffline(commitment: string): Promise<string> {
|
|
859
736
|
const proposal = this.proposals.get(commitment);
|
|
860
737
|
if (!proposal) {
|
|
861
738
|
throw new Error(`Proposal not found: ${commitment}`);
|
|
@@ -868,11 +745,9 @@ export class Multisig {
|
|
|
868
745
|
throw new Error('You have already signed this proposal');
|
|
869
746
|
}
|
|
870
747
|
|
|
871
|
-
const signatureHex = this.signer.signCommitment(commitment);
|
|
748
|
+
const signatureHex = await this.signer.signCommitment(commitment);
|
|
872
749
|
|
|
873
|
-
const sigEntry
|
|
874
|
-
? { scheme: 'ecdsa', signature: signatureHex, publicKey: this.signer.publicKey }
|
|
875
|
-
: { scheme: 'falcon', signature: signatureHex };
|
|
750
|
+
const sigEntry = toPsmSignature(this.signer.scheme, signatureHex, this.signer.publicKey);
|
|
876
751
|
proposal.signatures.push({
|
|
877
752
|
signerId: this.signer.commitment,
|
|
878
753
|
signature: sigEntry,
|
|
@@ -899,172 +774,16 @@ export class Multisig {
|
|
|
899
774
|
return this.exportTransactionProposalToJson(commitment);
|
|
900
775
|
}
|
|
901
776
|
|
|
902
|
-
private async
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
}
|
|
912
|
-
return { proposal, proposals };
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
private deltaToProposal(
|
|
916
|
-
delta: DeltaObject,
|
|
917
|
-
proposalId: string,
|
|
918
|
-
metadata?: ProposalMetadata,
|
|
919
|
-
existingSignatures?: TransactionProposalSignature[],
|
|
920
|
-
): TransactionProposal {
|
|
921
|
-
const resolvedMetadata: ProposalMetadata | undefined =
|
|
922
|
-
metadata ??
|
|
923
|
-
(delta.deltaPayload.metadata ? this.fromPsmMetadata(delta.deltaPayload.metadata) : undefined);
|
|
924
|
-
if (!resolvedMetadata) {
|
|
925
|
-
throw new Error('Missing proposal metadata');
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
const status = this.deltaStatusToProposalStatus(delta.status, resolvedMetadata.proposalType);
|
|
929
|
-
|
|
930
|
-
const signaturesFromStatus =
|
|
931
|
-
delta.status.status === 'pending'
|
|
932
|
-
? delta.status.cosignerSigs.map((s) => ({
|
|
933
|
-
signerId: s.signerId,
|
|
934
|
-
signature: s.signature,
|
|
935
|
-
timestamp: s.timestamp,
|
|
936
|
-
}))
|
|
937
|
-
: [];
|
|
938
|
-
|
|
939
|
-
const signaturesMap = new Map<string, TransactionProposalSignature>();
|
|
940
|
-
for (const sig of existingSignatures ?? []) {
|
|
941
|
-
signaturesMap.set(sig.signerId, sig);
|
|
942
|
-
}
|
|
943
|
-
for (const sig of signaturesFromStatus) {
|
|
944
|
-
signaturesMap.set(sig.signerId, sig);
|
|
945
|
-
}
|
|
946
|
-
const signatures = Array.from(signaturesMap.values());
|
|
947
|
-
|
|
948
|
-
return {
|
|
949
|
-
id: proposalId,
|
|
950
|
-
commitment: proposalId,
|
|
951
|
-
accountId: delta.accountId,
|
|
952
|
-
nonce: delta.nonce,
|
|
953
|
-
status,
|
|
954
|
-
txSummary: delta.deltaPayload.txSummary.data,
|
|
955
|
-
signatures,
|
|
956
|
-
metadata: resolvedMetadata,
|
|
957
|
-
};
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
private buildPsmMetadata(metadata: ProposalMetadata): PsmProposalMetadata {
|
|
961
|
-
const base: PsmProposalMetadata = {
|
|
962
|
-
proposalType: metadata.proposalType,
|
|
963
|
-
description: metadata.description,
|
|
964
|
-
salt: metadata.saltHex,
|
|
965
|
-
};
|
|
966
|
-
|
|
967
|
-
switch (metadata.proposalType) {
|
|
968
|
-
case 'consume_notes':
|
|
969
|
-
return {
|
|
970
|
-
...base,
|
|
971
|
-
noteIds: metadata.noteIds,
|
|
972
|
-
};
|
|
973
|
-
case 'p2id':
|
|
974
|
-
return {
|
|
975
|
-
...base,
|
|
976
|
-
recipientId: metadata.recipientId,
|
|
977
|
-
faucetId: metadata.faucetId,
|
|
978
|
-
amount: metadata.amount,
|
|
979
|
-
};
|
|
980
|
-
case 'switch_psm':
|
|
981
|
-
return {
|
|
982
|
-
...base,
|
|
983
|
-
targetThreshold: metadata.targetThreshold,
|
|
984
|
-
signerCommitments: metadata.targetSignerCommitments,
|
|
985
|
-
newPsmPubkey: metadata.newPsmPubkey,
|
|
986
|
-
newPsmEndpoint: metadata.newPsmEndpoint,
|
|
987
|
-
};
|
|
988
|
-
case 'add_signer':
|
|
989
|
-
case 'remove_signer':
|
|
990
|
-
case 'change_threshold':
|
|
991
|
-
return {
|
|
992
|
-
...base,
|
|
993
|
-
targetThreshold: metadata.targetThreshold,
|
|
994
|
-
signerCommitments: metadata.targetSignerCommitments,
|
|
995
|
-
};
|
|
996
|
-
case 'unknown':
|
|
997
|
-
return base;
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
private fromPsmMetadata(psm: PsmProposalMetadata): ProposalMetadata | undefined {
|
|
1002
|
-
if (!psm.proposalType) return undefined;
|
|
1003
|
-
const base = {
|
|
1004
|
-
description: psm.description ?? '',
|
|
1005
|
-
saltHex: psm.salt,
|
|
1006
|
-
};
|
|
1007
|
-
|
|
1008
|
-
switch (psm.proposalType) {
|
|
1009
|
-
case 'p2id':
|
|
1010
|
-
return {
|
|
1011
|
-
...base,
|
|
1012
|
-
proposalType: 'p2id',
|
|
1013
|
-
recipientId: psm.recipientId ?? '',
|
|
1014
|
-
faucetId: psm.faucetId ?? '',
|
|
1015
|
-
amount: psm.amount ?? '0',
|
|
1016
|
-
};
|
|
1017
|
-
case 'consume_notes':
|
|
1018
|
-
return {
|
|
1019
|
-
...base,
|
|
1020
|
-
proposalType: 'consume_notes',
|
|
1021
|
-
noteIds: psm.noteIds ?? [],
|
|
1022
|
-
};
|
|
1023
|
-
case 'switch_psm':
|
|
1024
|
-
return {
|
|
1025
|
-
...base,
|
|
1026
|
-
proposalType: 'switch_psm',
|
|
1027
|
-
newPsmPubkey: psm.newPsmPubkey ?? '',
|
|
1028
|
-
newPsmEndpoint: psm.newPsmEndpoint,
|
|
1029
|
-
targetThreshold: psm.targetThreshold,
|
|
1030
|
-
targetSignerCommitments: psm.signerCommitments,
|
|
1031
|
-
};
|
|
1032
|
-
case 'add_signer':
|
|
1033
|
-
case 'remove_signer':
|
|
1034
|
-
case 'change_threshold':
|
|
1035
|
-
return {
|
|
1036
|
-
...base,
|
|
1037
|
-
proposalType: psm.proposalType,
|
|
1038
|
-
targetThreshold: psm.targetThreshold ?? 0,
|
|
1039
|
-
targetSignerCommitments: psm.signerCommitments ?? [],
|
|
1040
|
-
};
|
|
1041
|
-
default:
|
|
1042
|
-
return undefined;
|
|
1043
|
-
}
|
|
777
|
+
private async createAndSyncFromRequest(
|
|
778
|
+
request: TransactionRequest,
|
|
779
|
+
metadata: ProposalMetadata,
|
|
780
|
+
nonce?: number,
|
|
781
|
+
): Promise<TransactionProposalResult> {
|
|
782
|
+
const summary = await executeForSummary(this.webClient, this._accountId, request);
|
|
783
|
+
const summaryBase64 = uint8ArrayToBase64(summary.serialize());
|
|
784
|
+
const proposalNonce = nonce ?? Date.now();
|
|
785
|
+
const proposal = await this.createProposal(proposalNonce, summaryBase64, metadata);
|
|
786
|
+
return { proposal, proposals: this.listTransactionProposals() };
|
|
1044
787
|
}
|
|
1045
788
|
|
|
1046
|
-
private deltaStatusToProposalStatus(status: DeltaStatus, proposalType?: ProposalType): TransactionProposalStatus {
|
|
1047
|
-
switch (status.status) {
|
|
1048
|
-
case 'pending': {
|
|
1049
|
-
const signaturesCollected = status.cosignerSigs.length;
|
|
1050
|
-
const signaturesRequired = proposalType
|
|
1051
|
-
? this.getEffectiveThreshold(proposalType)
|
|
1052
|
-
: this.threshold;
|
|
1053
|
-
if (signaturesCollected >= signaturesRequired) {
|
|
1054
|
-
return { type: 'ready' };
|
|
1055
|
-
}
|
|
1056
|
-
return {
|
|
1057
|
-
type: 'pending',
|
|
1058
|
-
signaturesCollected,
|
|
1059
|
-
signaturesRequired,
|
|
1060
|
-
signers: status.cosignerSigs.map((s) => s.signerId),
|
|
1061
|
-
};
|
|
1062
|
-
}
|
|
1063
|
-
case 'candidate':
|
|
1064
|
-
return { type: 'ready' };
|
|
1065
|
-
case 'canonical':
|
|
1066
|
-
case 'discarded':
|
|
1067
|
-
return { type: 'finalized' };
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
789
|
}
|