@openzeppelin/miden-multisig-client 0.13.0 → 0.13.2
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 +98 -119
- package/dist/account/builder.d.ts +18 -0
- package/dist/account/builder.d.ts.map +1 -1
- package/dist/account/builder.js +59 -29
- package/dist/account/builder.js.map +1 -1
- package/dist/account/builder.test.d.ts +2 -0
- package/dist/account/builder.test.d.ts.map +1 -0
- package/dist/account/builder.test.js +115 -0
- package/dist/account/builder.test.js.map +1 -0
- package/dist/account/index.d.ts +1 -1
- package/dist/account/index.d.ts.map +1 -1
- package/dist/account/index.js +1 -1
- package/dist/account/index.js.map +1 -1
- package/dist/account/masm/account-components/auth.d.ts +5 -0
- package/dist/account/masm/account-components/auth.d.ts.map +1 -0
- package/dist/account/masm/account-components/auth.js +67 -0
- package/dist/account/masm/account-components/auth.js.map +1 -0
- package/dist/account/masm/auth.d.ts +5 -0
- package/dist/account/masm/auth.d.ts.map +1 -0
- package/dist/account/masm/auth.js +1395 -0
- package/dist/account/masm/auth.js.map +1 -0
- package/dist/account/masm/index.d.ts +3 -0
- package/dist/account/masm/index.d.ts.map +1 -0
- package/dist/account/masm/index.js +5 -0
- package/dist/account/masm/index.js.map +1 -0
- package/dist/account/masm.d.ts +1 -4
- package/dist/account/masm.d.ts.map +1 -1
- package/dist/account/masm.js +3 -1034
- package/dist/account/masm.js.map +1 -1
- package/dist/account/storage.d.ts +2 -2
- package/dist/account/storage.d.ts.map +1 -1
- package/dist/account/storage.js +18 -16
- package/dist/account/storage.js.map +1 -1
- package/dist/client.d.ts +67 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +73 -22
- package/dist/client.js.map +1 -1
- package/dist/client.test.js +31 -32
- package/dist/client.test.js.map +1 -1
- package/dist/index.d.ts +54 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -9
- package/dist/index.js.map +1 -1
- package/dist/inspector.d.ts +32 -6
- package/dist/inspector.d.ts.map +1 -1
- package/dist/inspector.js +58 -23
- package/dist/inspector.js.map +1 -1
- package/dist/inspector.test.js +18 -18
- package/dist/inspector.test.js.map +1 -1
- package/dist/multisig/proposal/execution.d.ts +6 -5
- package/dist/multisig/proposal/execution.d.ts.map +1 -1
- package/dist/multisig/proposal/execution.js +49 -27
- package/dist/multisig/proposal/execution.js.map +1 -1
- package/dist/multisig/proposal/parser.d.ts +3 -3
- package/dist/multisig/proposal/parser.d.ts.map +1 -1
- package/dist/multisig/proposal/parser.js +23 -23
- package/dist/multisig/proposal/parser.js.map +1 -1
- package/dist/multisig/signing.d.ts +3 -3
- package/dist/multisig/signing.d.ts.map +1 -1
- package/dist/multisig/signing.js +3 -3
- package/dist/multisig/signing.js.map +1 -1
- package/dist/multisig.d.ts +187 -46
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +650 -289
- package/dist/multisig.js.map +1 -1
- package/dist/multisig.test.js +1680 -241
- package/dist/multisig.test.js.map +1 -1
- package/dist/procedures.d.ts +46 -24
- package/dist/procedures.d.ts.map +1 -1
- package/dist/procedures.js +46 -21
- package/dist/procedures.js.map +1 -1
- package/dist/proposal/factory.d.ts +18 -0
- package/dist/proposal/factory.d.ts.map +1 -0
- package/dist/proposal/factory.js +99 -0
- package/dist/proposal/factory.js.map +1 -0
- package/dist/proposal/metadata.d.ts +8 -0
- package/dist/proposal/metadata.d.ts.map +1 -0
- package/dist/proposal/metadata.js +156 -0
- package/dist/proposal/metadata.js.map +1 -0
- package/dist/proposal/signatures.d.ts +10 -0
- package/dist/proposal/signatures.d.ts.map +1 -0
- package/dist/proposal/signatures.js +54 -0
- package/dist/proposal/signatures.js.map +1 -0
- package/dist/signer.d.ts +2 -0
- package/dist/signer.d.ts.map +1 -1
- package/dist/signer.js +2 -0
- package/dist/signer.js.map +1 -1
- package/dist/signers/ecdsa.d.ts +3 -0
- package/dist/signers/ecdsa.d.ts.map +1 -1
- package/dist/signers/ecdsa.js +8 -4
- package/dist/signers/ecdsa.js.map +1 -1
- package/dist/signers/ecdsa.test.d.ts +2 -0
- package/dist/signers/ecdsa.test.d.ts.map +1 -0
- package/dist/signers/ecdsa.test.js +65 -0
- package/dist/signers/ecdsa.test.js.map +1 -0
- package/dist/signers/falcon.d.ts +3 -0
- package/dist/signers/falcon.d.ts.map +1 -1
- package/dist/signers/falcon.js +8 -4
- package/dist/signers/falcon.js.map +1 -1
- package/dist/signers/falcon.test.js +12 -0
- package/dist/signers/falcon.test.js.map +1 -1
- package/dist/signers/miden-wallet.d.ts +3 -1
- package/dist/signers/miden-wallet.d.ts.map +1 -1
- package/dist/signers/miden-wallet.js +11 -2
- package/dist/signers/miden-wallet.js.map +1 -1
- package/dist/signers/miden-wallet.test.js +26 -0
- package/dist/signers/miden-wallet.test.js.map +1 -1
- package/dist/signers/para.d.ts +3 -3
- package/dist/signers/para.d.ts.map +1 -1
- package/dist/signers/para.js +15 -6
- package/dist/signers/para.js.map +1 -1
- package/dist/signers/para.test.js +39 -0
- package/dist/signers/para.test.js.map +1 -1
- package/dist/transaction/consumeNotes.d.ts.map +1 -1
- package/dist/transaction/consumeNotes.js +1 -0
- package/dist/transaction/consumeNotes.js.map +1 -1
- package/dist/transaction/index.d.ts +2 -1
- package/dist/transaction/index.d.ts.map +1 -1
- package/dist/transaction/index.js +2 -1
- package/dist/transaction/index.js.map +1 -1
- package/dist/transaction/options.d.ts +1 -1
- package/dist/transaction/options.d.ts.map +1 -1
- package/dist/transaction/p2id.d.ts +1 -0
- package/dist/transaction/p2id.d.ts.map +1 -1
- package/dist/transaction/p2id.js +9 -3
- package/dist/transaction/p2id.js.map +1 -1
- package/dist/transaction/p2id.test.d.ts +2 -0
- package/dist/transaction/p2id.test.d.ts.map +1 -0
- package/dist/transaction/p2id.test.js +138 -0
- package/dist/transaction/p2id.test.js.map +1 -0
- package/dist/transaction/rpoRandomCoin.d.ts +7 -0
- package/dist/transaction/rpoRandomCoin.d.ts.map +1 -0
- package/dist/transaction/rpoRandomCoin.js +17 -0
- package/dist/transaction/rpoRandomCoin.js.map +1 -0
- package/dist/transaction/rpoRandomCoin.test.d.ts +2 -0
- package/dist/transaction/rpoRandomCoin.test.d.ts.map +1 -0
- package/dist/transaction/rpoRandomCoin.test.js +52 -0
- package/dist/transaction/rpoRandomCoin.test.js.map +1 -0
- package/dist/transaction/updateGuardian.d.ts +7 -0
- package/dist/transaction/updateGuardian.d.ts.map +1 -0
- package/dist/transaction/{updatePsm.js → updateGuardian.js} +15 -29
- package/dist/transaction/updateGuardian.js.map +1 -0
- package/dist/transaction/updateProcedureThreshold.d.ts +9 -0
- package/dist/transaction/updateProcedureThreshold.d.ts.map +1 -0
- package/dist/transaction/updateProcedureThreshold.js +55 -0
- package/dist/transaction/updateProcedureThreshold.js.map +1 -0
- package/dist/transaction/updateSigners.d.ts.map +1 -1
- package/dist/transaction/updateSigners.js +5 -23
- package/dist/transaction/updateSigners.js.map +1 -1
- package/dist/transaction.d.ts +2 -1
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +2 -1
- package/dist/transaction.js.map +1 -1
- package/dist/types/proposal.d.ts +32 -15
- package/dist/types/proposal.d.ts.map +1 -1
- package/dist/types.d.ts +24 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/digest.d.ts +5 -0
- package/dist/utils/digest.d.ts.map +1 -1
- package/dist/utils/digest.js +34 -1
- package/dist/utils/digest.js.map +1 -1
- package/dist/utils/digest.test.d.ts +2 -0
- package/dist/utils/digest.test.d.ts.map +1 -0
- package/dist/utils/digest.test.js +48 -0
- package/dist/utils/digest.test.js.map +1 -0
- package/dist/utils/signature.d.ts +3 -1
- package/dist/utils/signature.d.ts.map +1 -1
- package/dist/utils/signature.js +31 -6
- package/dist/utils/signature.js.map +1 -1
- package/dist/utils/word.test.js +1 -52
- package/dist/utils/word.test.js.map +1 -1
- package/masm/account_components/auth/multisig.masm +13 -0
- package/masm/account_components/auth/multisig_ecdsa.masm +13 -0
- package/masm/account_components/auth/multisig_guardian.masm +17 -0
- package/masm/account_components/auth/multisig_guardian_ecdsa.masm +17 -0
- package/masm/auth/guardian.masm +177 -0
- package/masm/auth/guardian_ecdsa.masm +178 -0
- package/masm/{multisig.masm → auth/multisig.masm} +149 -55
- package/masm/{multisig_ecdsa.masm → auth/multisig_ecdsa.masm} +148 -56
- package/package.json +11 -9
- package/src/account/builder.test.ts +165 -0
- package/src/account/builder.ts +71 -34
- package/src/account/index.ts +1 -1
- package/src/account/masm/account-components/auth.ts +70 -0
- package/src/account/masm/auth.ts +1398 -0
- package/src/account/masm/index.ts +5 -0
- package/src/account/masm.ts +3 -1040
- package/src/account/storage.ts +18 -16
- package/src/client.test.ts +31 -35
- package/src/client.ts +98 -26
- package/src/index.ts +84 -22
- package/src/inspector.test.ts +17 -17
- package/src/inspector.ts +63 -29
- package/src/multisig/proposal/execution.ts +102 -41
- package/src/multisig/proposal/parser.ts +26 -26
- package/src/multisig/signing.ts +4 -4
- package/src/multisig.test.ts +2097 -248
- package/src/multisig.ts +882 -365
- package/src/procedures.ts +50 -26
- package/src/proposal/factory.ts +171 -0
- package/src/proposal/metadata.ts +165 -0
- package/src/proposal/signatures.ts +68 -0
- package/src/signer.ts +2 -0
- package/src/signers/ecdsa.test.ts +80 -0
- package/src/signers/ecdsa.ts +15 -4
- package/src/signers/falcon.test.ts +19 -0
- package/src/signers/falcon.ts +16 -5
- package/src/signers/miden-wallet.test.ts +47 -0
- package/src/signers/miden-wallet.ts +18 -1
- package/src/signers/para.test.ts +57 -0
- package/src/signers/para.ts +26 -7
- package/src/transaction/consumeNotes.ts +1 -0
- package/src/transaction/index.ts +2 -2
- package/src/transaction/options.ts +1 -2
- package/src/transaction/p2id.test.ts +190 -0
- package/src/transaction/p2id.ts +11 -5
- package/src/transaction/rpoRandomCoin.test.ts +64 -0
- package/src/transaction/rpoRandomCoin.ts +24 -0
- package/src/transaction/{updatePsm.ts → updateGuardian.ts} +19 -32
- package/src/transaction/updateProcedureThreshold.ts +97 -0
- package/src/transaction/updateSigners.ts +12 -27
- package/src/transaction.ts +5 -3
- package/src/types/proposal.ts +43 -11
- package/src/types.ts +29 -11
- package/src/utils/digest.test.ts +55 -0
- package/src/utils/digest.ts +51 -1
- package/src/utils/signature.ts +47 -9
- package/src/utils/word.test.ts +1 -55
- package/dist/account.d.ts +0 -104
- package/dist/account.d.ts.map +0 -1
- package/dist/account.js +0 -136
- package/dist/account.js.map +0 -1
- package/dist/builder.d.ts +0 -54
- package/dist/builder.d.ts.map +0 -1
- package/dist/builder.js +0 -78
- package/dist/builder.js.map +0 -1
- package/dist/http.d.ts +0 -64
- package/dist/http.d.ts.map +0 -1
- package/dist/http.js +0 -162
- package/dist/http.js.map +0 -1
- package/dist/keystore.d.ts +0 -65
- package/dist/keystore.d.ts.map +0 -1
- package/dist/keystore.js +0 -121
- package/dist/keystore.js.map +0 -1
- package/dist/miden.d.ts +0 -9
- package/dist/miden.d.ts.map +0 -1
- package/dist/miden.js +0 -26
- package/dist/miden.js.map +0 -1
- package/dist/multisig/metadata.d.ts +0 -18
- package/dist/multisig/metadata.d.ts.map +0 -1
- package/dist/multisig/metadata.js +0 -100
- package/dist/multisig/metadata.js.map +0 -1
- package/dist/multisig/metadata.test.d.ts +0 -2
- package/dist/multisig/metadata.test.d.ts.map +0 -1
- package/dist/multisig/metadata.test.js +0 -323
- package/dist/multisig/metadata.test.js.map +0 -1
- package/dist/signer.test.d.ts +0 -2
- package/dist/signer.test.d.ts.map +0 -1
- package/dist/signer.test.js +0 -117
- package/dist/signer.test.js.map +0 -1
- package/dist/transaction/updatePsm.d.ts +0 -7
- package/dist/transaction/updatePsm.d.ts.map +0 -1
- package/dist/transaction/updatePsm.js.map +0 -1
- package/dist/transport/http.d.ts +0 -64
- package/dist/transport/http.d.ts.map +0 -1
- package/dist/transport/http.js +0 -162
- package/dist/transport/http.js.map +0 -1
- package/dist/transport/index.d.ts +0 -5
- package/dist/transport/index.d.ts.map +0 -1
- package/dist/transport/index.js +0 -5
- package/dist/transport/index.js.map +0 -1
- package/masm/psm.masm +0 -178
- package/masm/psm_ecdsa.masm +0 -179
package/src/inspector.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account Inspector - Inspects account storage to detect multisig configuration.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { Account, Word } from '@miden-sdk/miden-sdk';
|
|
2
6
|
import { base64ToUint8Array } from './utils/encoding.js';
|
|
3
7
|
import { wordElementToBigInt, wordToHex } from './utils/word.js';
|
|
4
8
|
import { getProcedureRoot, getProcedureNames, type ProcedureName } from './procedures.js';
|
|
5
|
-
import type { SignatureScheme } from './types.js';
|
|
6
9
|
|
|
10
|
+
// Storage slot names matching the MASM definitions
|
|
7
11
|
const MULTISIG_SLOT_NAMES = {
|
|
8
12
|
THRESHOLD_CONFIG: 'openzeppelin::multisig::threshold_config',
|
|
9
13
|
SIGNER_PUBLIC_KEYS: 'openzeppelin::multisig::signer_public_keys',
|
|
@@ -11,9 +15,9 @@ const MULTISIG_SLOT_NAMES = {
|
|
|
11
15
|
PROCEDURE_THRESHOLDS: 'openzeppelin::multisig::procedure_thresholds',
|
|
12
16
|
} as const;
|
|
13
17
|
|
|
14
|
-
const
|
|
15
|
-
SELECTOR: 'openzeppelin::
|
|
16
|
-
PUBLIC_KEY: 'openzeppelin::
|
|
18
|
+
const GUARDIAN_SLOT_NAMES = {
|
|
19
|
+
SELECTOR: 'openzeppelin::guardian::selector',
|
|
20
|
+
PUBLIC_KEY: 'openzeppelin::guardian::public_key',
|
|
17
21
|
} as const;
|
|
18
22
|
|
|
19
23
|
export interface VaultBalance {
|
|
@@ -25,23 +29,48 @@ export interface DetectedMultisigConfig {
|
|
|
25
29
|
threshold: number;
|
|
26
30
|
numSigners: number;
|
|
27
31
|
signerCommitments: string[];
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
guardianEnabled: boolean;
|
|
33
|
+
guardianCommitment: string | null;
|
|
30
34
|
vaultBalances: VaultBalance[];
|
|
31
35
|
procedureThresholds: Map<ProcedureName, number>;
|
|
32
|
-
signatureScheme: SignatureScheme;
|
|
33
36
|
}
|
|
34
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Inspects an account to detect its multisig configuration.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* // From base64-encoded state
|
|
44
|
+
* const config = AccountInspector.fromBase64(stateDataBase64);
|
|
45
|
+
* console.log(`${config.threshold}-of-${config.numSigners} multisig`);
|
|
46
|
+
*
|
|
47
|
+
* // From Miden SDK Account
|
|
48
|
+
* const config = AccountInspector.fromAccount(account);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
35
51
|
export class AccountInspector {
|
|
36
52
|
private constructor() {}
|
|
37
53
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Inspect a base64-encoded serialized account.
|
|
56
|
+
*
|
|
57
|
+
* @param base64Data - Base64-encoded Account bytes
|
|
58
|
+
* @returns Detected multisig configuration
|
|
59
|
+
*/
|
|
60
|
+
static fromBase64(base64Data: string): DetectedMultisigConfig {
|
|
61
|
+
const bytes = base64ToUint8Array(base64Data);
|
|
62
|
+
const account = Account.deserialize(bytes);
|
|
63
|
+
return AccountInspector.fromAccount(account);
|
|
42
64
|
}
|
|
43
65
|
|
|
44
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Inspect a Miden SDK Account object.
|
|
68
|
+
*
|
|
69
|
+
* @param account - The Account object from Miden SDK
|
|
70
|
+
* @returns Detected multisig configuration
|
|
71
|
+
*/
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
+
static fromAccount(account: Account): DetectedMultisigConfig {
|
|
45
74
|
const storage = account.storage();
|
|
46
75
|
|
|
47
76
|
const slot0 = storage.getItem(MULTISIG_SLOT_NAMES.THRESHOLD_CONFIG) as Word;
|
|
@@ -56,26 +85,28 @@ export class AccountInspector {
|
|
|
56
85
|
if (commitment) {
|
|
57
86
|
signerCommitments.push(wordToHex(commitment));
|
|
58
87
|
}
|
|
59
|
-
} catch {
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.warn(error);
|
|
60
90
|
}
|
|
61
91
|
}
|
|
62
92
|
|
|
63
|
-
let
|
|
64
|
-
let
|
|
93
|
+
let guardianEnabled = false;
|
|
94
|
+
let guardianCommitment: string | null = null;
|
|
65
95
|
|
|
66
96
|
try {
|
|
67
|
-
const
|
|
68
|
-
const selector = Number(wordElementToBigInt(
|
|
69
|
-
|
|
97
|
+
const guardianSlot0 = storage.getItem(GUARDIAN_SLOT_NAMES.SELECTOR) as Word;
|
|
98
|
+
const selector = Number(wordElementToBigInt(guardianSlot0, 0));
|
|
99
|
+
guardianEnabled = selector === 1;
|
|
70
100
|
|
|
71
|
-
if (
|
|
101
|
+
if (guardianEnabled) {
|
|
72
102
|
const zeroKey = new Word(new BigUint64Array([0n, 0n, 0n, 0n]));
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
75
|
-
|
|
103
|
+
const guardianKey = storage.getMapItem(GUARDIAN_SLOT_NAMES.PUBLIC_KEY, zeroKey) as Word;
|
|
104
|
+
if (guardianKey) {
|
|
105
|
+
guardianCommitment = wordToHex(guardianKey);
|
|
76
106
|
}
|
|
77
107
|
}
|
|
78
|
-
} catch {
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.warn(error);
|
|
79
110
|
}
|
|
80
111
|
|
|
81
112
|
const vaultBalances: VaultBalance[] = [];
|
|
@@ -88,13 +119,16 @@ export class AccountInspector {
|
|
|
88
119
|
amount: BigInt(asset.amount()),
|
|
89
120
|
});
|
|
90
121
|
}
|
|
91
|
-
} catch {
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.warn(error);
|
|
92
124
|
}
|
|
93
125
|
|
|
126
|
+
// Read procedure threshold overrides from storage slot 3
|
|
127
|
+
// Storage layout: slot 3 is a map of PROC_ROOT => [threshold, 0, 0, 0]
|
|
94
128
|
const procedureThresholds = new Map<ProcedureName, number>();
|
|
95
|
-
for (const procName of getProcedureNames(
|
|
129
|
+
for (const procName of getProcedureNames()) {
|
|
96
130
|
try {
|
|
97
|
-
const rootHex = getProcedureRoot(procName
|
|
131
|
+
const rootHex = getProcedureRoot(procName);
|
|
98
132
|
const rootWord = Word.fromHex(rootHex);
|
|
99
133
|
const value = storage.getMapItem(MULTISIG_SLOT_NAMES.PROCEDURE_THRESHOLDS, rootWord) as Word;
|
|
100
134
|
if (value) {
|
|
@@ -104,6 +138,7 @@ export class AccountInspector {
|
|
|
104
138
|
}
|
|
105
139
|
}
|
|
106
140
|
} catch {
|
|
141
|
+
// Procedure threshold not set - use default
|
|
107
142
|
}
|
|
108
143
|
}
|
|
109
144
|
|
|
@@ -111,11 +146,10 @@ export class AccountInspector {
|
|
|
111
146
|
threshold,
|
|
112
147
|
numSigners,
|
|
113
148
|
signerCommitments,
|
|
114
|
-
|
|
115
|
-
|
|
149
|
+
guardianEnabled,
|
|
150
|
+
guardianCommitment,
|
|
116
151
|
vaultBalances,
|
|
117
152
|
procedureThresholds,
|
|
118
|
-
signatureScheme,
|
|
119
153
|
};
|
|
120
154
|
}
|
|
121
155
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type DeltaObject, type
|
|
1
|
+
import { type DeltaObject, type GuardianHttpClient } from '@openzeppelin/guardian-client';
|
|
2
2
|
import type { WebClient, TransactionRequest } from '@miden-sdk/miden-sdk';
|
|
3
3
|
import {
|
|
4
4
|
AccountId,
|
|
@@ -12,7 +12,8 @@ import type { ProposalType, TransactionProposal } from '../../types.js';
|
|
|
12
12
|
import {
|
|
13
13
|
buildConsumeNotesTransactionRequest,
|
|
14
14
|
buildP2idTransactionRequest,
|
|
15
|
-
|
|
15
|
+
buildUpdateGuardianTransactionRequest,
|
|
16
|
+
buildUpdateProcedureThresholdTransactionRequest,
|
|
16
17
|
buildUpdateSignersTransactionRequest,
|
|
17
18
|
} from '../../transaction.js';
|
|
18
19
|
import { base64ToUint8Array, normalizeHexWord } from '../../utils/encoding.js';
|
|
@@ -39,11 +40,11 @@ interface ExecuteProposalWorkflowParams {
|
|
|
39
40
|
accountId: string;
|
|
40
41
|
threshold: number;
|
|
41
42
|
signerCommitments: string[];
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
guardianCommitment: string;
|
|
44
|
+
guardianPublicKey?: string;
|
|
44
45
|
signatureScheme: 'falcon' | 'ecdsa';
|
|
45
46
|
getEffectiveThreshold: (proposalType: ProposalType) => number;
|
|
46
|
-
|
|
47
|
+
guardian: GuardianHttpClient;
|
|
47
48
|
webClient: WebClient;
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -56,12 +57,12 @@ export async function executeProposalWorkflow(
|
|
|
56
57
|
params.getEffectiveThreshold,
|
|
57
58
|
);
|
|
58
59
|
|
|
59
|
-
const
|
|
60
|
+
const isSwitchGuardian = params.proposal.metadata.proposalType === 'switch_guardian';
|
|
60
61
|
const executionSource = await resolveExecutionSource(
|
|
61
|
-
params.
|
|
62
|
+
params.guardian,
|
|
62
63
|
params.accountId,
|
|
63
64
|
params.proposal,
|
|
64
|
-
|
|
65
|
+
isSwitchGuardian,
|
|
65
66
|
);
|
|
66
67
|
const executionData = prepareExecutionData(executionSource.txSummaryBase64);
|
|
67
68
|
|
|
@@ -71,12 +72,12 @@ export async function executeProposalWorkflow(
|
|
|
71
72
|
executionData.txCommitmentHex,
|
|
72
73
|
);
|
|
73
74
|
|
|
74
|
-
if (!
|
|
75
|
-
await
|
|
76
|
-
params.
|
|
75
|
+
if (!isSwitchGuardian && executionSource.delta) {
|
|
76
|
+
await appendGuardianAckAdvice(
|
|
77
|
+
params.guardian,
|
|
77
78
|
executionSource.delta,
|
|
78
|
-
params.
|
|
79
|
-
params.
|
|
79
|
+
params.guardianCommitment,
|
|
80
|
+
params.guardianPublicKey,
|
|
80
81
|
params.signatureScheme,
|
|
81
82
|
executionData.txCommitmentHex,
|
|
82
83
|
adviceMap,
|
|
@@ -91,6 +92,50 @@ export async function executeProposalWorkflow(
|
|
|
91
92
|
await submitTransaction(params.webClient, params.accountId, finalRequest);
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
|
|
96
|
+
export async function createTransactionProposalRequest(
|
|
97
|
+
params: ExecuteProposalWorkflowParams,
|
|
98
|
+
): Promise<TransactionRequest> {
|
|
99
|
+
ensureProposalReady(
|
|
100
|
+
params.proposal,
|
|
101
|
+
params.threshold,
|
|
102
|
+
params.getEffectiveThreshold,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const isSwitchGuardian = params.proposal.metadata.proposalType === 'switch_guardian';
|
|
106
|
+
const executionSource = await resolveExecutionSource(
|
|
107
|
+
params.guardian,
|
|
108
|
+
params.accountId,
|
|
109
|
+
params.proposal,
|
|
110
|
+
isSwitchGuardian,
|
|
111
|
+
);
|
|
112
|
+
const executionData = prepareExecutionData(executionSource.txSummaryBase64);
|
|
113
|
+
|
|
114
|
+
const adviceMap = buildCosignerAdviceMap(
|
|
115
|
+
params.proposal,
|
|
116
|
+
params.signerCommitments,
|
|
117
|
+
executionData.txCommitmentHex,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
if (!isSwitchGuardian && executionSource.delta) {
|
|
121
|
+
await appendGuardianAckAdvice(
|
|
122
|
+
params.guardian,
|
|
123
|
+
executionSource.delta,
|
|
124
|
+
params.guardianCommitment,
|
|
125
|
+
params.guardianPublicKey,
|
|
126
|
+
params.signatureScheme,
|
|
127
|
+
executionData.txCommitmentHex,
|
|
128
|
+
adviceMap,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return await buildFinalRequest(
|
|
133
|
+
params,
|
|
134
|
+
executionData.saltHex,
|
|
135
|
+
adviceMap,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
94
139
|
function ensureProposalReady(
|
|
95
140
|
proposal: TransactionProposal,
|
|
96
141
|
defaultThreshold: number,
|
|
@@ -107,16 +152,16 @@ function ensureProposalReady(
|
|
|
107
152
|
}
|
|
108
153
|
|
|
109
154
|
async function resolveExecutionSource(
|
|
110
|
-
|
|
155
|
+
guardian: GuardianHttpClient,
|
|
111
156
|
accountId: string,
|
|
112
157
|
proposal: TransactionProposal,
|
|
113
|
-
|
|
158
|
+
isSwitchGuardian: boolean,
|
|
114
159
|
): Promise<ResolveExecutionSourceResult> {
|
|
115
|
-
if (
|
|
160
|
+
if (isSwitchGuardian) {
|
|
116
161
|
return { txSummaryBase64: proposal.txSummary };
|
|
117
162
|
}
|
|
118
163
|
|
|
119
|
-
const deltas = await
|
|
164
|
+
const deltas = await guardian.getDeltaProposals(accountId);
|
|
120
165
|
const delta = deltas.find(
|
|
121
166
|
(d) => computeCommitmentFromTxSummary(d.deltaPayload.txSummary.data) === proposal.commitment,
|
|
122
167
|
);
|
|
@@ -170,14 +215,17 @@ function buildCosignerAdviceMap(
|
|
|
170
215
|
);
|
|
171
216
|
const signature = Signature.deserialize(sigBytes);
|
|
172
217
|
const txCommitment = Word.fromHex(normalizeHexWord(txCommitmentHex));
|
|
173
|
-
const
|
|
174
|
-
cosignerSig.signature.scheme === 'ecdsa'
|
|
218
|
+
const ecdsaPublicKey =
|
|
219
|
+
cosignerSig.signature.scheme === 'ecdsa'
|
|
220
|
+
? cosignerSig.signature.publicKey
|
|
221
|
+
: undefined;
|
|
222
|
+
const isEcdsa = cosignerSig.signature.scheme === 'ecdsa' && Boolean(ecdsaPublicKey);
|
|
175
223
|
|
|
176
224
|
const { key, values } = buildSignatureAdviceEntry(
|
|
177
225
|
signerCommitment,
|
|
178
226
|
txCommitment,
|
|
179
227
|
signature,
|
|
180
|
-
|
|
228
|
+
ecdsaPublicKey,
|
|
181
229
|
isEcdsa ? cosignerSig.signature.signature : undefined,
|
|
182
230
|
);
|
|
183
231
|
adviceMap.insert(key, new FeltArray(values));
|
|
@@ -186,11 +234,11 @@ function buildCosignerAdviceMap(
|
|
|
186
234
|
return adviceMap;
|
|
187
235
|
}
|
|
188
236
|
|
|
189
|
-
async function
|
|
190
|
-
|
|
237
|
+
async function appendGuardianAckAdvice(
|
|
238
|
+
guardian: GuardianHttpClient,
|
|
191
239
|
delta: DeltaObject,
|
|
192
|
-
|
|
193
|
-
|
|
240
|
+
guardianCommitmentHex: string,
|
|
241
|
+
guardianPublicKey: string | undefined,
|
|
194
242
|
defaultAckScheme: 'falcon' | 'ecdsa',
|
|
195
243
|
txCommitmentHex: string,
|
|
196
244
|
adviceMap: AdviceMap,
|
|
@@ -200,31 +248,31 @@ async function appendPsmAckAdvice(
|
|
|
200
248
|
deltaPayload: delta.deltaPayload.txSummary,
|
|
201
249
|
};
|
|
202
250
|
|
|
203
|
-
const pushResult = await
|
|
251
|
+
const pushResult = await guardian.pushDelta(executionDelta);
|
|
204
252
|
const ackSigHex = pushResult.ackSig;
|
|
205
253
|
if (!ackSigHex) {
|
|
206
|
-
throw new Error('
|
|
254
|
+
throw new Error('GUARDIAN did not return acknowledgment signature');
|
|
207
255
|
}
|
|
208
256
|
|
|
209
|
-
const
|
|
257
|
+
const guardianAckScheme: 'ecdsa' | 'falcon' =
|
|
210
258
|
(pushResult.ackScheme as 'ecdsa' | 'falcon') || defaultAckScheme;
|
|
211
|
-
const ackPubkey = pushResult.ackPubkey ||
|
|
212
|
-
const
|
|
259
|
+
const ackPubkey = pushResult.ackPubkey || guardianPublicKey;
|
|
260
|
+
const normalizedGuardianCommitment = normalizeHexWord(guardianCommitmentHex);
|
|
213
261
|
|
|
214
|
-
if (
|
|
262
|
+
if (guardianAckScheme === 'ecdsa' && ackPubkey) {
|
|
215
263
|
const derived = tryComputeEcdsaCommitmentHex(ackPubkey);
|
|
216
|
-
if (derived && derived !==
|
|
217
|
-
throw new Error('
|
|
264
|
+
if (derived && derived !== normalizedGuardianCommitment) {
|
|
265
|
+
throw new Error('GUARDIAN public key commitment mismatch');
|
|
218
266
|
}
|
|
219
267
|
}
|
|
220
268
|
|
|
221
|
-
const
|
|
222
|
-
const ackSigBytes = signatureHexToBytes(ackSigHex,
|
|
269
|
+
const guardianCommitment = Word.fromHex(normalizedGuardianCommitment);
|
|
270
|
+
const ackSigBytes = signatureHexToBytes(ackSigHex, guardianAckScheme);
|
|
223
271
|
const ackSignature = Signature.deserialize(ackSigBytes);
|
|
224
272
|
const txCommitment = Word.fromHex(normalizeHexWord(txCommitmentHex));
|
|
225
|
-
const isAckEcdsa =
|
|
273
|
+
const isAckEcdsa = guardianAckScheme === 'ecdsa' && ackPubkey;
|
|
226
274
|
const { key, values } = buildSignatureAdviceEntry(
|
|
227
|
-
|
|
275
|
+
guardianCommitment,
|
|
228
276
|
txCommitment,
|
|
229
277
|
ackSignature,
|
|
230
278
|
isAckEcdsa ? ackPubkey : undefined,
|
|
@@ -255,15 +303,28 @@ async function buildFinalRequest(
|
|
|
255
303
|
);
|
|
256
304
|
return request;
|
|
257
305
|
}
|
|
258
|
-
case '
|
|
259
|
-
if (!metadata.
|
|
306
|
+
case 'switch_guardian': {
|
|
307
|
+
if (!metadata.newGuardianPubkey) {
|
|
260
308
|
throw new Error(
|
|
261
|
-
'Proposal missing
|
|
309
|
+
'Proposal missing newGuardianPubkey. Was it created with createSwitchGuardianProposal?',
|
|
262
310
|
);
|
|
263
311
|
}
|
|
264
|
-
const { request } = await
|
|
312
|
+
const { request } = await buildUpdateGuardianTransactionRequest(
|
|
265
313
|
params.webClient,
|
|
266
|
-
metadata.
|
|
314
|
+
metadata.newGuardianPubkey,
|
|
315
|
+
{
|
|
316
|
+
salt: normalizedSalt,
|
|
317
|
+
signatureAdviceMap: adviceMap,
|
|
318
|
+
signatureScheme: params.signatureScheme,
|
|
319
|
+
},
|
|
320
|
+
);
|
|
321
|
+
return request;
|
|
322
|
+
}
|
|
323
|
+
case 'update_procedure_threshold': {
|
|
324
|
+
const { request } = await buildUpdateProcedureThresholdTransactionRequest(
|
|
325
|
+
params.webClient,
|
|
326
|
+
metadata.targetProcedure,
|
|
327
|
+
metadata.targetThreshold,
|
|
267
328
|
{
|
|
268
329
|
salt: normalizedSalt,
|
|
269
330
|
signatureAdviceMap: adviceMap,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
DeltaObject,
|
|
3
3
|
DeltaStatus,
|
|
4
|
-
ProposalMetadata as
|
|
5
|
-
} from '@openzeppelin/
|
|
4
|
+
ProposalMetadata as GuardianProposalMetadata,
|
|
5
|
+
} from '@openzeppelin/guardian-client';
|
|
6
6
|
import type {
|
|
7
7
|
ProposalMetadata,
|
|
8
8
|
ProposalType,
|
|
@@ -11,8 +11,8 @@ import type {
|
|
|
11
11
|
TransactionProposalStatus,
|
|
12
12
|
} from '../../types.js';
|
|
13
13
|
|
|
14
|
-
export function
|
|
15
|
-
const base:
|
|
14
|
+
export function buildGuardianMetadata(metadata: ProposalMetadata): GuardianProposalMetadata {
|
|
15
|
+
const base: GuardianProposalMetadata = {
|
|
16
16
|
proposalType: metadata.proposalType,
|
|
17
17
|
description: metadata.description,
|
|
18
18
|
salt: metadata.saltHex,
|
|
@@ -31,13 +31,13 @@ export function buildPsmMetadata(metadata: ProposalMetadata): PsmProposalMetadat
|
|
|
31
31
|
faucetId: metadata.faucetId,
|
|
32
32
|
amount: metadata.amount,
|
|
33
33
|
};
|
|
34
|
-
case '
|
|
34
|
+
case 'switch_guardian':
|
|
35
35
|
return {
|
|
36
36
|
...base,
|
|
37
37
|
targetThreshold: metadata.targetThreshold,
|
|
38
38
|
signerCommitments: metadata.targetSignerCommitments,
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
newGuardianPubkey: metadata.newGuardianPubkey,
|
|
40
|
+
newGuardianEndpoint: metadata.newGuardianEndpoint,
|
|
41
41
|
};
|
|
42
42
|
case 'add_signer':
|
|
43
43
|
case 'remove_signer':
|
|
@@ -54,46 +54,46 @@ export function buildPsmMetadata(metadata: ProposalMetadata): PsmProposalMetadat
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
export function
|
|
58
|
-
if (!
|
|
57
|
+
export function fromGuardianMetadata(guardian: GuardianProposalMetadata): ProposalMetadata | undefined {
|
|
58
|
+
if (!guardian.proposalType) return undefined;
|
|
59
59
|
|
|
60
60
|
const base = {
|
|
61
|
-
description:
|
|
62
|
-
saltHex:
|
|
61
|
+
description: guardian.description ?? '',
|
|
62
|
+
saltHex: guardian.salt,
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
switch (
|
|
65
|
+
switch (guardian.proposalType) {
|
|
66
66
|
case 'p2id':
|
|
67
67
|
return {
|
|
68
68
|
...base,
|
|
69
69
|
proposalType: 'p2id',
|
|
70
|
-
recipientId:
|
|
71
|
-
faucetId:
|
|
72
|
-
amount:
|
|
70
|
+
recipientId: guardian.recipientId ?? '',
|
|
71
|
+
faucetId: guardian.faucetId ?? '',
|
|
72
|
+
amount: guardian.amount ?? '0',
|
|
73
73
|
};
|
|
74
74
|
case 'consume_notes':
|
|
75
75
|
return {
|
|
76
76
|
...base,
|
|
77
77
|
proposalType: 'consume_notes',
|
|
78
|
-
noteIds:
|
|
78
|
+
noteIds: guardian.noteIds ?? [],
|
|
79
79
|
};
|
|
80
|
-
case '
|
|
80
|
+
case 'switch_guardian':
|
|
81
81
|
return {
|
|
82
82
|
...base,
|
|
83
|
-
proposalType: '
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
targetThreshold:
|
|
87
|
-
targetSignerCommitments:
|
|
83
|
+
proposalType: 'switch_guardian',
|
|
84
|
+
newGuardianPubkey: guardian.newGuardianPubkey ?? '',
|
|
85
|
+
newGuardianEndpoint: guardian.newGuardianEndpoint,
|
|
86
|
+
targetThreshold: guardian.targetThreshold,
|
|
87
|
+
targetSignerCommitments: guardian.signerCommitments,
|
|
88
88
|
};
|
|
89
89
|
case 'add_signer':
|
|
90
90
|
case 'remove_signer':
|
|
91
91
|
case 'change_threshold':
|
|
92
92
|
return {
|
|
93
93
|
...base,
|
|
94
|
-
proposalType:
|
|
95
|
-
targetThreshold:
|
|
96
|
-
targetSignerCommitments:
|
|
94
|
+
proposalType: guardian.proposalType,
|
|
95
|
+
targetThreshold: guardian.targetThreshold ?? 0,
|
|
96
|
+
targetSignerCommitments: guardian.signerCommitments ?? [],
|
|
97
97
|
};
|
|
98
98
|
default:
|
|
99
99
|
return undefined;
|
|
@@ -178,7 +178,7 @@ export function resolveMetadata(
|
|
|
178
178
|
): ProposalMetadata | undefined {
|
|
179
179
|
if (existingMetadata) return existingMetadata;
|
|
180
180
|
if (!delta.deltaPayload.metadata) return undefined;
|
|
181
|
-
return
|
|
181
|
+
return fromGuardianMetadata(delta.deltaPayload.metadata);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
export function signatureRequirementForProposal(
|
package/src/multisig/signing.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ProposalSignature, Signer } from '@openzeppelin/
|
|
1
|
+
import type { ProposalSignature, Signer } from '@openzeppelin/guardian-client';
|
|
2
2
|
import type { SignatureScheme } from '../types.js';
|
|
3
3
|
|
|
4
|
-
export function
|
|
4
|
+
export function toGuardianSignature(
|
|
5
5
|
scheme: SignatureScheme,
|
|
6
6
|
signatureHex: string,
|
|
7
7
|
publicKey?: string,
|
|
@@ -15,10 +15,10 @@ export function toPsmSignature(
|
|
|
15
15
|
return { scheme: 'falcon', signature: signatureHex };
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export async function
|
|
18
|
+
export async function buildGuardianSignatureFromSigner(
|
|
19
19
|
signer: Signer,
|
|
20
20
|
commitment: string,
|
|
21
21
|
): Promise<ProposalSignature> {
|
|
22
22
|
const signatureHex = await signer.signCommitment(commitment);
|
|
23
|
-
return
|
|
23
|
+
return toGuardianSignature(signer.scheme, signatureHex, signer.publicKey);
|
|
24
24
|
}
|