@openzeppelin/miden-multisig-client 0.13.3 → 0.13.4
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/dist/multisig.d.ts +4 -1
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +50 -42
- package/dist/multisig.js.map +1 -1
- package/dist/multisig.test.js +464 -0
- package/dist/multisig.test.js.map +1 -1
- package/package.json +2 -2
- package/src/multisig.test.ts +555 -0
- package/src/multisig.ts +66 -53
package/src/multisig.ts
CHANGED
|
@@ -866,24 +866,75 @@ export class Multisig {
|
|
|
866
866
|
return this.proposals.get(proposalId) ?? this.proposals.get(normalizedProposalId);
|
|
867
867
|
}
|
|
868
868
|
|
|
869
|
+
async createTransactionProposalRequest(proposalId: string): Promise<TransactionRequest> {
|
|
870
|
+
const { finalRequest } = await this.prepareProposalExecution(proposalId);
|
|
871
|
+
return finalRequest;
|
|
872
|
+
}
|
|
873
|
+
|
|
869
874
|
/**
|
|
870
875
|
* Execute a proposal that has enough signatures.
|
|
871
876
|
*
|
|
872
877
|
* @param proposalId - The proposal commitment/ID
|
|
873
878
|
*/
|
|
874
879
|
async executeProposal(proposalId: string): Promise<void> {
|
|
875
|
-
const proposal = this.
|
|
880
|
+
const { metadata, finalRequest, proposal } = await this.prepareProposalExecution(proposalId);
|
|
881
|
+
|
|
882
|
+
const accountId = AccountId.fromHex(this._accountId);
|
|
883
|
+
const result = await this.webClient.executeTransaction(accountId, finalRequest);
|
|
884
|
+
const proven = await this.webClient.proveTransaction(result, null);
|
|
885
|
+
const submissionHeight = await this.webClient.submitProvenTransaction(proven, result);
|
|
886
|
+
await this.webClient.applyTransaction(result, submissionHeight);
|
|
887
|
+
|
|
888
|
+
if (metadata.proposalType === 'switch_guardian') {
|
|
889
|
+
if (!metadata.newGuardianEndpoint || !metadata.newGuardianPubkey) {
|
|
890
|
+
throw new Error('Switch GUARDIAN proposal metadata is incomplete after execution');
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
try {
|
|
894
|
+
await this.webClient.syncState();
|
|
895
|
+
|
|
896
|
+
const updatedAccount = await this.webClient.getAccount(accountId);
|
|
897
|
+
if (!updatedAccount) {
|
|
898
|
+
throw new Error(
|
|
899
|
+
`Updated account ${this._accountId} is missing from local client`
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
const updatedStateBase64 = uint8ArrayToBase64(updatedAccount.serialize());
|
|
904
|
+
const nextGuardian = new GuardianHttpClient(metadata.newGuardianEndpoint);
|
|
905
|
+
this.setGuardianClient(nextGuardian);
|
|
906
|
+
this.guardianPublicKey = metadata.newGuardianPubkey;
|
|
907
|
+
|
|
908
|
+
await this.registerOnGuardian(updatedStateBase64);
|
|
909
|
+
} catch (error) {
|
|
910
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
911
|
+
throw new Error(
|
|
912
|
+
`Transaction executed successfully but failed to register on new GUARDIAN: ${message}`
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
proposal.status = 'finalized';
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
private getLocalProposal(proposalId: string): Proposal | undefined {
|
|
921
|
+
const normalizedProposalId = normalizeHexWord(proposalId);
|
|
922
|
+
return this.proposals.get(proposalId) ?? this.proposals.get(normalizedProposalId);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
private async prepareProposalExecution(
|
|
926
|
+
proposalId: string,
|
|
927
|
+
): Promise<{ finalRequest: TransactionRequest; metadata: ProposalMetadata; proposal: Proposal }> {
|
|
928
|
+
const proposal = this.getLocalProposal(proposalId);
|
|
876
929
|
if (!proposal) {
|
|
877
930
|
throw new Error(`Proposal not found: ${proposalId}`);
|
|
878
931
|
}
|
|
879
932
|
|
|
933
|
+
this.proposalFactory().assertAccountId(proposal.accountId);
|
|
880
934
|
await this.verifyProposalMetadataBinding(proposal);
|
|
881
935
|
|
|
882
|
-
const
|
|
883
|
-
const effectiveThreshold = proposalType
|
|
884
|
-
? this.getEffectiveThreshold(proposalType)
|
|
885
|
-
: this.threshold;
|
|
886
|
-
|
|
936
|
+
const metadata = proposal.metadata;
|
|
937
|
+
const effectiveThreshold = this.getEffectiveThreshold(metadata.proposalType);
|
|
887
938
|
const signatureContext = `Invalid proposal signatures for ${proposalId}`;
|
|
888
939
|
const signaturesForExecution = new ProposalSignatures(
|
|
889
940
|
proposal.signatures,
|
|
@@ -895,7 +946,8 @@ export class Multisig {
|
|
|
895
946
|
throw new Error('Proposal is not ready for execution. Still pending signatures.');
|
|
896
947
|
}
|
|
897
948
|
|
|
898
|
-
const isSwitchGuardian = proposalType === 'switch_guardian';
|
|
949
|
+
const isSwitchGuardian = metadata.proposalType === 'switch_guardian';
|
|
950
|
+
const normalizedProposalId = normalizeHexWord(proposal.id);
|
|
899
951
|
|
|
900
952
|
let txSummaryBase64: string;
|
|
901
953
|
let delta: DeltaObject | undefined;
|
|
@@ -903,7 +955,7 @@ export class Multisig {
|
|
|
903
955
|
if (isSwitchGuardian) {
|
|
904
956
|
txSummaryBase64 = proposal.txSummary;
|
|
905
957
|
} else {
|
|
906
|
-
delta = await this.guardian.getDeltaProposal(this._accountId,
|
|
958
|
+
delta = await this.guardian.getDeltaProposal(this._accountId, normalizedProposalId);
|
|
907
959
|
txSummaryBase64 = delta.deltaPayload.txSummary.data;
|
|
908
960
|
}
|
|
909
961
|
|
|
@@ -911,12 +963,13 @@ export class Multisig {
|
|
|
911
963
|
const txSummary = TransactionSummary.deserialize(txSummaryBytes);
|
|
912
964
|
const saltHex = txSummary.salt().toHex();
|
|
913
965
|
const txCommitmentHex = txSummary.toCommitment().toHex();
|
|
966
|
+
const normalizedTxCommitmentHex = normalizeHexWord(txCommitmentHex);
|
|
914
967
|
const normalizedSignerCommitments = new Set(
|
|
915
968
|
this.signerCommitments.map((commitment) => normalizeHexWord(commitment)),
|
|
916
969
|
);
|
|
917
|
-
|
|
918
970
|
const adviceMap = new AdviceMap();
|
|
919
971
|
const adviceMapKeys = new Set<string>();
|
|
972
|
+
const createTxCommitmentWord = (): Word => Word.fromHex(normalizedTxCommitmentHex);
|
|
920
973
|
|
|
921
974
|
for (const cosignerSig of signaturesForExecution) {
|
|
922
975
|
let signerCommitmentHex = normalizeHexWord(cosignerSig.signerId);
|
|
@@ -949,10 +1002,9 @@ export class Multisig {
|
|
|
949
1002
|
cosignerSig.signature.scheme,
|
|
950
1003
|
);
|
|
951
1004
|
const signature = Signature.deserialize(sigBytes);
|
|
952
|
-
const txCommitment = Word.fromHex(normalizeHexWord(txCommitmentHex));
|
|
953
1005
|
const { key, values } = buildSignatureAdviceEntry(
|
|
954
1006
|
signerCommitment,
|
|
955
|
-
|
|
1007
|
+
createTxCommitmentWord(),
|
|
956
1008
|
signature,
|
|
957
1009
|
ecdsaPublicKey,
|
|
958
1010
|
cosignerSig.signature.scheme === 'ecdsa'
|
|
@@ -993,10 +1045,9 @@ export class Multisig {
|
|
|
993
1045
|
}
|
|
994
1046
|
const ackSigBytes = signatureHexToBytes(ackSigHex, ackScheme);
|
|
995
1047
|
const ackSignature = Signature.deserialize(ackSigBytes);
|
|
996
|
-
const txCommitmentForAck = Word.fromHex(normalizeHexWord(txCommitmentHex));
|
|
997
1048
|
const { key: ackKey, values: ackValues } = buildSignatureAdviceEntry(
|
|
998
1049
|
guardianCommitment,
|
|
999
|
-
|
|
1050
|
+
createTxCommitmentWord(),
|
|
1000
1051
|
ackSignature,
|
|
1001
1052
|
ackScheme === 'ecdsa' ? ackPubkey : undefined,
|
|
1002
1053
|
ackScheme === 'ecdsa' ? ackSigHex : undefined,
|
|
@@ -1009,13 +1060,10 @@ export class Multisig {
|
|
|
1009
1060
|
adviceMap.insert(ackKey, new FeltArray(ackValues));
|
|
1010
1061
|
}
|
|
1011
1062
|
|
|
1012
|
-
const metadata = proposal.metadata;
|
|
1013
|
-
if (!metadata) {
|
|
1014
|
-
throw new Error('Proposal missing metadata');
|
|
1015
|
-
}
|
|
1016
1063
|
if (metadata.proposalType === 'switch_guardian') {
|
|
1017
1064
|
await this.verifyGuardianEndpointCommitment(metadata.newGuardianEndpoint, metadata.newGuardianPubkey);
|
|
1018
1065
|
}
|
|
1066
|
+
|
|
1019
1067
|
const executionSalt = Word.fromHex(normalizeHexWord(saltHex));
|
|
1020
1068
|
const finalRequest = await this.buildTransactionRequestFromMetadata(
|
|
1021
1069
|
metadata,
|
|
@@ -1023,42 +1071,7 @@ export class Multisig {
|
|
|
1023
1071
|
adviceMap,
|
|
1024
1072
|
);
|
|
1025
1073
|
|
|
1026
|
-
|
|
1027
|
-
const result = await this.webClient.executeTransaction(accountId, finalRequest);
|
|
1028
|
-
const proven = await this.webClient.proveTransaction(result, null);
|
|
1029
|
-
const submissionHeight = await this.webClient.submitProvenTransaction(proven, result);
|
|
1030
|
-
await this.webClient.applyTransaction(result, submissionHeight);
|
|
1031
|
-
|
|
1032
|
-
if (metadata.proposalType === 'switch_guardian') {
|
|
1033
|
-
if (!metadata.newGuardianEndpoint || !metadata.newGuardianPubkey) {
|
|
1034
|
-
throw new Error('Switch GUARDIAN proposal metadata is incomplete after execution');
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
try {
|
|
1038
|
-
await this.webClient.syncState();
|
|
1039
|
-
|
|
1040
|
-
const updatedAccount = await this.webClient.getAccount(accountId);
|
|
1041
|
-
if (!updatedAccount) {
|
|
1042
|
-
throw new Error(
|
|
1043
|
-
`Updated account ${this._accountId} is missing from local client`
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
const updatedStateBase64 = uint8ArrayToBase64(updatedAccount.serialize());
|
|
1048
|
-
const nextGuardian = new GuardianHttpClient(metadata.newGuardianEndpoint);
|
|
1049
|
-
this.setGuardianClient(nextGuardian);
|
|
1050
|
-
this.guardianPublicKey = metadata.newGuardianPubkey;
|
|
1051
|
-
|
|
1052
|
-
await this.registerOnGuardian(updatedStateBase64);
|
|
1053
|
-
} catch (error) {
|
|
1054
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1055
|
-
throw new Error(
|
|
1056
|
-
`Transaction executed successfully but failed to register on new GUARDIAN: ${message}`
|
|
1057
|
-
);
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
proposal.status = 'finalized';
|
|
1074
|
+
return { finalRequest, metadata, proposal };
|
|
1062
1075
|
}
|
|
1063
1076
|
|
|
1064
1077
|
/**
|