@aztec/node-keystore 2.0.3 → 2.1.0-rc.10
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/dest/keystore_manager.d.ts +14 -3
- package/dest/keystore_manager.d.ts.map +1 -1
- package/dest/keystore_manager.js +122 -42
- package/dest/loader.js +22 -3
- package/dest/schemas.d.ts +391 -94
- package/dest/schemas.d.ts.map +1 -1
- package/dest/schemas.js +22 -2
- package/dest/signer.d.ts +9 -1
- package/dest/signer.d.ts.map +1 -1
- package/dest/signer.js +52 -1
- package/dest/types.d.ts +17 -6
- package/dest/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/keystore_manager.ts +148 -55
- package/src/loader.ts +23 -3
- package/src/schemas.ts +22 -3
- package/src/signer.ts +77 -1
- package/src/types.ts +18 -6
|
@@ -8,7 +8,7 @@ import { Buffer32 } from '@aztec/foundation/buffer';
|
|
|
8
8
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
9
|
import type { Signature } from '@aztec/foundation/eth-signature';
|
|
10
10
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
11
|
-
import type { TypedDataDefinition } from 'viem';
|
|
11
|
+
import type { TypedDataDefinition } from '@spalladino/viem';
|
|
12
12
|
import type { EthAccounts, EthRemoteSignerConfig, KeyStore, ProverKeyStore, ValidatorKeyStore as ValidatorKeystoreConfig } from './types.js';
|
|
13
13
|
/**
|
|
14
14
|
* Error thrown when keystore operations fail
|
|
@@ -28,6 +28,11 @@ export declare class KeystoreManager {
|
|
|
28
28
|
* @param keystore Parsed keystore configuration
|
|
29
29
|
*/
|
|
30
30
|
constructor(keystore: KeyStore);
|
|
31
|
+
/**
|
|
32
|
+
* Validates all remote signers in the keystore are accessible and have the required addresses.
|
|
33
|
+
* Should be called after construction if validation is needed.
|
|
34
|
+
*/
|
|
35
|
+
validateSigners(): Promise<void>;
|
|
31
36
|
/**
|
|
32
37
|
* Validates that attester addresses are unique across all validators
|
|
33
38
|
* Only checks simple private key attesters, not JSON-V3 or mnemonic attesters,
|
|
@@ -40,6 +45,10 @@ export declare class KeystoreManager {
|
|
|
40
45
|
* This is used at construction time to check for obvious duplicates without throwing for invalid inputs.
|
|
41
46
|
*/
|
|
42
47
|
private extractAddressesWithoutSensitiveOperations;
|
|
48
|
+
/**
|
|
49
|
+
* Extract addresses from EthAccounts without sensitive operations (no decryption/derivation).
|
|
50
|
+
*/
|
|
51
|
+
private extractAddressesFromEthAccountsNonSensitive;
|
|
43
52
|
/**
|
|
44
53
|
* Create signers for validator attester accounts
|
|
45
54
|
*/
|
|
@@ -69,9 +78,9 @@ export declare class KeystoreManager {
|
|
|
69
78
|
*/
|
|
70
79
|
getValidatorCount(): number;
|
|
71
80
|
/**
|
|
72
|
-
* Get coinbase address for validator (falls back to
|
|
81
|
+
* Get coinbase address for validator (falls back to the specific attester address)
|
|
73
82
|
*/
|
|
74
|
-
getCoinbaseAddress(validatorIndex: number): EthAddress;
|
|
83
|
+
getCoinbaseAddress(validatorIndex: number, attesterAddress: EthAddress): EthAddress;
|
|
75
84
|
/**
|
|
76
85
|
* Get fee recipient for validator
|
|
77
86
|
*/
|
|
@@ -124,5 +133,7 @@ export declare class KeystoreManager {
|
|
|
124
133
|
* Precedence: account-level override > validator-level config > file-level default
|
|
125
134
|
*/
|
|
126
135
|
getEffectiveRemoteSignerConfig(validatorIndex: number, attesterAddress: EthAddress): EthRemoteSignerConfig | undefined;
|
|
136
|
+
/** Extract ETH accounts from AttesterAccounts */
|
|
137
|
+
private extractEthAccountsFromAttester;
|
|
127
138
|
}
|
|
128
139
|
//# sourceMappingURL=keystore_manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keystore_manager.d.ts","sourceRoot":"","sources":["../src/keystore_manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"keystore_manager.d.ts","sourceRoot":"","sources":["../src/keystore_manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAO5D,OAAO,KAAK,EAGV,WAAW,EAEX,qBAAqB,EAErB,QAAQ,EAER,cAAc,EACd,iBAAiB,IAAI,uBAAuB,EAC7C,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAGpB,KAAK,CAAC,EAAE,KAAK;gBAD7B,OAAO,EAAE,MAAM,EACC,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IAEpC;;;;OAIG;gBACS,QAAQ,EAAE,QAAQ;IAK9B;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAwEtC;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IAkBvC;;;OAGG;IACH,OAAO,CAAC,0CAA0C;IAKlD;;OAEG;IACH,OAAO,CAAC,2CAA2C;IA+CnD;;OAEG;IACH,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,EAAE;IAM1D;;OAEG;IACH,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,EAAE;IAc3D,kCAAkC,IAAI,SAAS,EAAE;IAWjD;;OAEG;IACH,oBAAoB,IAAI,SAAS,EAAE;IAQnC;;OAEG;IACH,mBAAmB,IAAI;QAAE,EAAE,EAAE,UAAU,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,SAAS,EAAE,CAAA;KAAE,GAAG,SAAS;IAiCvF;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,uBAAuB;IAOpD;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,kBAAkB,CAAC,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,UAAU,GAAG,UAAU;IAWnF;;OAEG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,YAAY;IAKrD;;;OAGG;IACH,kBAAkB,IAAI,WAAW,GAAG,SAAS;IAI7C;;;OAGG;IACH,eAAe,IAAI,cAAc,GAAG,SAAS;IAI7C;;;OAGG;IACH,uCAAuC,IAAI,IAAI;IAqB/C;;OAEG;IACH,OAAO,CAAC,4BAA4B;IA+BpC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA2ClC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkD9B;;OAEG;IACH,OAAO,CAAC,gCAAgC;IAwBxC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA8BjC;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IAI3E;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,SAAS,CAAC;IAI1F;;;OAGG;IACH,8BAA8B,CAC5B,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,UAAU,GAC1B,qBAAqB,GAAG,SAAS;IA0GpC,iDAAiD;IACjD,OAAO,CAAC,8BAA8B;CAyBvC"}
|
package/dest/keystore_manager.js
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Manages keystore configuration and delegates signing operations to appropriate signers.
|
|
5
5
|
*/ import { Buffer32 } from '@aztec/foundation/buffer';
|
|
6
6
|
import { Wallet } from '@ethersproject/wallet';
|
|
7
|
+
import { mnemonicToAccount } from '@spalladino/viem/accounts';
|
|
7
8
|
import { readFileSync, readdirSync, statSync } from 'fs';
|
|
8
9
|
import { extname, join } from 'path';
|
|
9
|
-
import { mnemonicToAccount } from 'viem/accounts';
|
|
10
10
|
import { ethPrivateKeySchema } from './schemas.js';
|
|
11
11
|
import { LocalSigner, RemoteSigner } from './signer.js';
|
|
12
12
|
/**
|
|
@@ -31,6 +31,70 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
31
31
|
this.validateUniqueAttesterAddresses();
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
+
* Validates all remote signers in the keystore are accessible and have the required addresses.
|
|
35
|
+
* Should be called after construction if validation is needed.
|
|
36
|
+
*/ async validateSigners() {
|
|
37
|
+
// Collect all remote signers with their addresses grouped by URL
|
|
38
|
+
const remoteSignersByUrl = new Map();
|
|
39
|
+
// Helper to extract remote signer URL from config
|
|
40
|
+
const getUrl = (config)=>{
|
|
41
|
+
return typeof config === 'string' ? config : config.remoteSignerUrl;
|
|
42
|
+
};
|
|
43
|
+
// Helper to collect remote signers from accounts
|
|
44
|
+
const collectRemoteSigners = (accounts, defaultRemoteSigner)=>{
|
|
45
|
+
const processAccount = (account)=>{
|
|
46
|
+
if (typeof account === 'object' && !('path' in account) && !('mnemonic' in account)) {
|
|
47
|
+
// This is a remote signer account
|
|
48
|
+
const remoteSigner = account;
|
|
49
|
+
const address = 'address' in remoteSigner ? remoteSigner.address : remoteSigner;
|
|
50
|
+
let url;
|
|
51
|
+
if ('remoteSignerUrl' in remoteSigner && remoteSigner.remoteSignerUrl) {
|
|
52
|
+
url = remoteSigner.remoteSignerUrl;
|
|
53
|
+
} else if (defaultRemoteSigner) {
|
|
54
|
+
url = getUrl(defaultRemoteSigner);
|
|
55
|
+
} else {
|
|
56
|
+
return; // No remote signer URL available
|
|
57
|
+
}
|
|
58
|
+
if (!remoteSignersByUrl.has(url)) {
|
|
59
|
+
remoteSignersByUrl.set(url, new Set());
|
|
60
|
+
}
|
|
61
|
+
remoteSignersByUrl.get(url).add(address.toString());
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
if (Array.isArray(accounts)) {
|
|
65
|
+
accounts.forEach((account)=>collectRemoteSigners(account, defaultRemoteSigner));
|
|
66
|
+
} else if (typeof accounts === 'object' && 'mnemonic' in accounts) {
|
|
67
|
+
// Skip mnemonic configs
|
|
68
|
+
} else {
|
|
69
|
+
processAccount(accounts);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
// Collect from validators
|
|
73
|
+
const validatorCount = this.getValidatorCount();
|
|
74
|
+
for(let i = 0; i < validatorCount; i++){
|
|
75
|
+
const validator = this.getValidator(i);
|
|
76
|
+
const remoteSigner = validator.remoteSigner || this.keystore.remoteSigner;
|
|
77
|
+
collectRemoteSigners(this.extractEthAccountsFromAttester(validator.attester), remoteSigner);
|
|
78
|
+
if (validator.publisher) {
|
|
79
|
+
collectRemoteSigners(validator.publisher, remoteSigner);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Collect from slasher
|
|
83
|
+
if (this.keystore.slasher) {
|
|
84
|
+
collectRemoteSigners(this.keystore.slasher, this.keystore.remoteSigner);
|
|
85
|
+
}
|
|
86
|
+
// Collect from prover
|
|
87
|
+
if (this.keystore.prover && typeof this.keystore.prover === 'object' && 'publisher' in this.keystore.prover) {
|
|
88
|
+
collectRemoteSigners(this.keystore.prover.publisher, this.keystore.remoteSigner);
|
|
89
|
+
}
|
|
90
|
+
// Validate each remote signer URL with all its addresses
|
|
91
|
+
for (const [url, addresses] of remoteSignersByUrl.entries()){
|
|
92
|
+
if (addresses.size > 0) {
|
|
93
|
+
await RemoteSigner.validateAccess(url, Array.from(addresses));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
34
98
|
* Validates that attester addresses are unique across all validators
|
|
35
99
|
* Only checks simple private key attesters, not JSON-V3 or mnemonic attesters,
|
|
36
100
|
* these are validated when decrypting the JSON-V3 keystore files
|
|
@@ -54,32 +118,31 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
54
118
|
* Best-effort address extraction that avoids decryption/derivation (no JSON-V3 or mnemonic processing).
|
|
55
119
|
* This is used at construction time to check for obvious duplicates without throwing for invalid inputs.
|
|
56
120
|
*/ extractAddressesWithoutSensitiveOperations(accounts) {
|
|
121
|
+
const ethAccounts = this.extractEthAccountsFromAttester(accounts);
|
|
122
|
+
return this.extractAddressesFromEthAccountsNonSensitive(ethAccounts);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Extract addresses from EthAccounts without sensitive operations (no decryption/derivation).
|
|
126
|
+
*/ extractAddressesFromEthAccountsNonSensitive(accounts) {
|
|
57
127
|
const results = [];
|
|
58
128
|
const handleAccount = (account)=>{
|
|
59
|
-
// String cases: private key or address or remote signer address
|
|
60
129
|
if (typeof account === 'string') {
|
|
61
130
|
if (account.startsWith('0x') && account.length === 66) {
|
|
62
|
-
// Private key -> derive address locally without external deps
|
|
63
131
|
try {
|
|
64
132
|
const signer = new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
|
|
65
133
|
results.push(signer.address);
|
|
66
134
|
} catch {
|
|
67
|
-
//
|
|
135
|
+
// ignore invalid private key at construction time
|
|
68
136
|
}
|
|
69
|
-
return;
|
|
70
137
|
}
|
|
71
|
-
// Any other string cannot be confidently resolved here
|
|
72
138
|
return;
|
|
73
139
|
}
|
|
74
|
-
// JSON V3 keystore: skip (requires decryption)
|
|
75
140
|
if ('path' in account) {
|
|
76
141
|
return;
|
|
77
142
|
}
|
|
78
|
-
// Mnemonic: skip (requires derivation and may throw on invalid mnemonics)
|
|
79
143
|
if ('mnemonic' in account) {
|
|
80
144
|
return;
|
|
81
145
|
}
|
|
82
|
-
// Remote signer account. If it contains 'address' then extract, otherwise it IS the address
|
|
83
146
|
const remoteSigner = account;
|
|
84
147
|
if ('address' in remoteSigner) {
|
|
85
148
|
results.push(remoteSigner.address);
|
|
@@ -89,11 +152,13 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
89
152
|
};
|
|
90
153
|
if (Array.isArray(accounts)) {
|
|
91
154
|
for (const account of accounts){
|
|
92
|
-
|
|
93
|
-
results.push(...subResults);
|
|
155
|
+
handleAccount(account);
|
|
94
156
|
}
|
|
95
157
|
return results;
|
|
96
158
|
}
|
|
159
|
+
if (typeof accounts === 'object' && accounts !== null && 'mnemonic' in accounts) {
|
|
160
|
+
return results;
|
|
161
|
+
}
|
|
97
162
|
handleAccount(accounts);
|
|
98
163
|
return results;
|
|
99
164
|
}
|
|
@@ -101,7 +166,8 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
101
166
|
* Create signers for validator attester accounts
|
|
102
167
|
*/ createAttesterSigners(validatorIndex) {
|
|
103
168
|
const validator = this.getValidator(validatorIndex);
|
|
104
|
-
|
|
169
|
+
const ethAccounts = this.extractEthAccountsFromAttester(validator.attester);
|
|
170
|
+
return this.createSignersFromEthAccounts(ethAccounts, validator.remoteSigner || this.keystore.remoteSigner);
|
|
105
171
|
}
|
|
106
172
|
/**
|
|
107
173
|
* Create signers for validator publisher accounts (falls back to attester if not specified)
|
|
@@ -173,18 +239,14 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
173
239
|
return this.keystore.validators?.length || 0;
|
|
174
240
|
}
|
|
175
241
|
/**
|
|
176
|
-
* Get coinbase address for validator (falls back to
|
|
177
|
-
*/ getCoinbaseAddress(validatorIndex) {
|
|
242
|
+
* Get coinbase address for validator (falls back to the specific attester address)
|
|
243
|
+
*/ getCoinbaseAddress(validatorIndex, attesterAddress) {
|
|
178
244
|
const validator = this.getValidator(validatorIndex);
|
|
179
245
|
if (validator.coinbase) {
|
|
180
246
|
return validator.coinbase;
|
|
181
247
|
}
|
|
182
|
-
// Fall back to
|
|
183
|
-
|
|
184
|
-
if (attesterSigners.length === 0) {
|
|
185
|
-
throw new KeystoreError(`No attester signers found for validator ${validatorIndex}`);
|
|
186
|
-
}
|
|
187
|
-
return attesterSigners[0].address;
|
|
248
|
+
// Fall back to the specific attester address
|
|
249
|
+
return attesterAddress;
|
|
188
250
|
}
|
|
189
251
|
/**
|
|
190
252
|
* Get fee recipient for validator
|
|
@@ -212,7 +274,7 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
212
274
|
const validatorCount = this.getValidatorCount();
|
|
213
275
|
for(let validatorIndex = 0; validatorIndex < validatorCount; validatorIndex++){
|
|
214
276
|
const validator = this.getValidator(validatorIndex);
|
|
215
|
-
const signers = this.createSignersFromEthAccounts(validator.attester, validator.remoteSigner || this.keystore.remoteSigner);
|
|
277
|
+
const signers = this.createSignersFromEthAccounts(this.extractEthAccountsFromAttester(validator.attester), validator.remoteSigner || this.keystore.remoteSigner);
|
|
216
278
|
for (const signer of signers){
|
|
217
279
|
const address = signer.address.toString().toLowerCase();
|
|
218
280
|
if (seenAddresses.has(address)) {
|
|
@@ -466,34 +528,52 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
466
528
|
// Just an address, use defaults
|
|
467
529
|
return validator.remoteSigner || this.keystore.remoteSigner;
|
|
468
530
|
};
|
|
469
|
-
//
|
|
470
|
-
const
|
|
531
|
+
// Normalize attester to EthAccounts and search
|
|
532
|
+
const normalized = this.extractEthAccountsFromAttester(validator.attester);
|
|
533
|
+
const findInEthAccounts = (accs)=>{
|
|
534
|
+
if (typeof accs === 'string') {
|
|
535
|
+
return checkAccount(accs);
|
|
536
|
+
}
|
|
537
|
+
if (Array.isArray(accs)) {
|
|
538
|
+
for (const a of accs){
|
|
539
|
+
const res = checkAccount(a);
|
|
540
|
+
if (res !== undefined) {
|
|
541
|
+
return res;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
if (typeof accs === 'object' && accs !== null && 'mnemonic' in accs) {
|
|
547
|
+
// mnemonic-derived keys are local signers; no remote signer config
|
|
548
|
+
return undefined;
|
|
549
|
+
}
|
|
550
|
+
return checkAccount(accs);
|
|
551
|
+
};
|
|
552
|
+
return findInEthAccounts(normalized);
|
|
553
|
+
}
|
|
554
|
+
/** Extract ETH accounts from AttesterAccounts */ extractEthAccountsFromAttester(attester) {
|
|
471
555
|
if (typeof attester === 'string') {
|
|
472
|
-
|
|
473
|
-
return result === undefined ? undefined : result;
|
|
556
|
+
return attester;
|
|
474
557
|
}
|
|
475
558
|
if (Array.isArray(attester)) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (
|
|
479
|
-
|
|
559
|
+
const out = [];
|
|
560
|
+
for (const item of attester){
|
|
561
|
+
if (typeof item === 'string') {
|
|
562
|
+
out.push(item);
|
|
563
|
+
} else if ('eth' in item) {
|
|
564
|
+
out.push(item.eth);
|
|
565
|
+
} else if (!('mnemonic' in item)) {
|
|
566
|
+
out.push(item);
|
|
480
567
|
}
|
|
481
568
|
}
|
|
482
|
-
return
|
|
569
|
+
return out;
|
|
483
570
|
}
|
|
484
|
-
// Mnemonic configuration
|
|
485
571
|
if ('mnemonic' in attester) {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
return matches ? undefined : undefined;
|
|
491
|
-
} catch {
|
|
492
|
-
return undefined;
|
|
493
|
-
}
|
|
572
|
+
return attester;
|
|
573
|
+
}
|
|
574
|
+
if ('eth' in attester) {
|
|
575
|
+
return attester.eth;
|
|
494
576
|
}
|
|
495
|
-
|
|
496
|
-
const result = checkAccount(attester);
|
|
497
|
-
return result === undefined ? undefined : result;
|
|
577
|
+
return attester;
|
|
498
578
|
}
|
|
499
579
|
}
|
package/dest/loader.js
CHANGED
|
@@ -236,19 +236,38 @@ const logger = createLogger('node-keystore:loader');
|
|
|
236
236
|
* @param attester The attester configuration in any supported shape.
|
|
237
237
|
* @returns Array of string keys used to detect duplicates.
|
|
238
238
|
*/ function extractAttesterKeys(attester) {
|
|
239
|
+
// String forms (private key or other) - return as-is for coarse uniqueness
|
|
239
240
|
if (typeof attester === 'string') {
|
|
240
241
|
return [
|
|
241
242
|
attester
|
|
242
243
|
];
|
|
243
244
|
}
|
|
245
|
+
// Arrays of attester items
|
|
244
246
|
if (Array.isArray(attester)) {
|
|
245
|
-
|
|
247
|
+
const keys = [];
|
|
248
|
+
for (const item of attester){
|
|
249
|
+
keys.push(...extractAttesterKeys(item));
|
|
250
|
+
}
|
|
251
|
+
return keys;
|
|
246
252
|
}
|
|
247
|
-
if (attester && typeof attester === 'object'
|
|
253
|
+
if (attester && typeof attester === 'object') {
|
|
254
|
+
const obj = attester;
|
|
255
|
+
// New shape: { eth: EthAccount, bls?: BLSAccount }
|
|
256
|
+
if ('eth' in obj) {
|
|
257
|
+
return extractAttesterKeys(obj.eth);
|
|
258
|
+
}
|
|
259
|
+
// Remote signer account object shape: { address, remoteSignerUrl?, ... }
|
|
260
|
+
if ('address' in obj) {
|
|
261
|
+
return [
|
|
262
|
+
String(obj.address)
|
|
263
|
+
];
|
|
264
|
+
}
|
|
265
|
+
// Mnemonic or other object shapes: stringify
|
|
248
266
|
return [
|
|
249
|
-
attester
|
|
267
|
+
JSON.stringify(attester)
|
|
250
268
|
];
|
|
251
269
|
}
|
|
270
|
+
// Fallback stringify for anything else (null/undefined)
|
|
252
271
|
return [
|
|
253
272
|
JSON.stringify(attester)
|
|
254
273
|
];
|