@aztec/node-keystore 4.0.0-nightly.20250907 → 4.0.0-nightly.20260107
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/config.d.ts +1 -1
- package/dest/index.d.ts +1 -1
- package/dest/keystore_manager.d.ts +19 -7
- package/dest/keystore_manager.d.ts.map +1 -1
- package/dest/keystore_manager.js +198 -125
- package/dest/loader.d.ts +1 -1
- package/dest/loader.d.ts.map +1 -1
- package/dest/loader.js +93 -18
- package/dest/schemas.d.ts +2893 -990
- package/dest/schemas.d.ts.map +1 -1
- package/dest/schemas.js +102 -40
- package/dest/signer.d.ts +10 -17
- package/dest/signer.d.ts.map +1 -1
- package/dest/signer.js +58 -6
- package/dest/types.d.ts +46 -27
- package/dest/types.d.ts.map +1 -1
- package/dest/types.js +1 -1
- package/package.json +10 -7
- package/src/keystore_manager.ts +242 -145
- package/src/loader.ts +95 -11
- package/src/schemas.ts +135 -58
- package/src/signer.ts +84 -11
- package/src/types.ts +50 -32
package/src/keystore_manager.ts
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Manages keystore configuration and delegates signing operations to appropriate signers.
|
|
5
5
|
*/
|
|
6
|
-
import type { EthSigner } from '@aztec/ethereum';
|
|
6
|
+
import type { EthSigner } from '@aztec/ethereum/eth-signer';
|
|
7
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
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
10
11
|
|
|
11
12
|
import { Wallet } from '@ethersproject/wallet';
|
|
12
13
|
import { readFileSync, readdirSync, statSync } from 'fs';
|
|
@@ -14,16 +15,17 @@ import { extname, join } from 'path';
|
|
|
14
15
|
import type { TypedDataDefinition } from 'viem';
|
|
15
16
|
import { mnemonicToAccount } from 'viem/accounts';
|
|
16
17
|
|
|
18
|
+
import { ethPrivateKeySchema } from './schemas.js';
|
|
17
19
|
import { LocalSigner, RemoteSigner } from './signer.js';
|
|
18
20
|
import type {
|
|
21
|
+
AttesterAccounts,
|
|
22
|
+
EncryptedKeyFileConfig,
|
|
19
23
|
EthAccount,
|
|
20
24
|
EthAccounts,
|
|
21
|
-
EthJsonKeyFileV3Config,
|
|
22
|
-
EthMnemonicConfig,
|
|
23
|
-
EthPrivateKey,
|
|
24
25
|
EthRemoteSignerAccount,
|
|
25
26
|
EthRemoteSignerConfig,
|
|
26
27
|
KeyStore,
|
|
28
|
+
MnemonicConfig,
|
|
27
29
|
ProverKeyStore,
|
|
28
30
|
ValidatorKeyStore as ValidatorKeystoreConfig,
|
|
29
31
|
} from './types.js';
|
|
@@ -57,6 +59,82 @@ export class KeystoreManager {
|
|
|
57
59
|
this.validateUniqueAttesterAddresses();
|
|
58
60
|
}
|
|
59
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Validates all remote signers in the keystore are accessible and have the required addresses.
|
|
64
|
+
* Should be called after construction if validation is needed.
|
|
65
|
+
*/
|
|
66
|
+
async validateSigners(): Promise<void> {
|
|
67
|
+
// Collect all remote signers with their addresses grouped by URL
|
|
68
|
+
const remoteSignersByUrl = new Map<string, Set<string>>();
|
|
69
|
+
|
|
70
|
+
// Helper to extract remote signer URL from config
|
|
71
|
+
const getUrl = (config: EthRemoteSignerConfig): string => {
|
|
72
|
+
return typeof config === 'string' ? config : config.remoteSignerUrl;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Helper to collect remote signers from accounts
|
|
76
|
+
const collectRemoteSigners = (accounts: EthAccounts, defaultRemoteSigner?: EthRemoteSignerConfig): void => {
|
|
77
|
+
const processAccount = (account: EthAccount): void => {
|
|
78
|
+
if (typeof account === 'object' && !('path' in account) && !('mnemonic' in (account as any))) {
|
|
79
|
+
// This is a remote signer account
|
|
80
|
+
const remoteSigner = account as EthRemoteSignerAccount;
|
|
81
|
+
const address = 'address' in remoteSigner ? remoteSigner.address : remoteSigner;
|
|
82
|
+
|
|
83
|
+
let url: string;
|
|
84
|
+
if ('remoteSignerUrl' in remoteSigner && remoteSigner.remoteSignerUrl) {
|
|
85
|
+
url = remoteSigner.remoteSignerUrl;
|
|
86
|
+
} else if (defaultRemoteSigner) {
|
|
87
|
+
url = getUrl(defaultRemoteSigner);
|
|
88
|
+
} else {
|
|
89
|
+
return; // No remote signer URL available
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!remoteSignersByUrl.has(url)) {
|
|
93
|
+
remoteSignersByUrl.set(url, new Set());
|
|
94
|
+
}
|
|
95
|
+
remoteSignersByUrl.get(url)!.add(address.toString());
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
if (Array.isArray(accounts)) {
|
|
100
|
+
accounts.forEach(account => collectRemoteSigners(account, defaultRemoteSigner));
|
|
101
|
+
} else if (typeof accounts === 'object' && 'mnemonic' in accounts) {
|
|
102
|
+
// Skip mnemonic configs
|
|
103
|
+
} else {
|
|
104
|
+
processAccount(accounts as EthAccount);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Collect from validators
|
|
109
|
+
const validatorCount = this.getValidatorCount();
|
|
110
|
+
for (let i = 0; i < validatorCount; i++) {
|
|
111
|
+
const validator = this.getValidator(i);
|
|
112
|
+
const remoteSigner = validator.remoteSigner || this.keystore.remoteSigner;
|
|
113
|
+
|
|
114
|
+
collectRemoteSigners(this.extractEthAccountsFromAttester(validator.attester), remoteSigner);
|
|
115
|
+
if (validator.publisher) {
|
|
116
|
+
collectRemoteSigners(validator.publisher, remoteSigner);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Collect from slasher
|
|
121
|
+
if (this.keystore.slasher) {
|
|
122
|
+
collectRemoteSigners(this.keystore.slasher, this.keystore.remoteSigner);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Collect from prover
|
|
126
|
+
if (this.keystore.prover && typeof this.keystore.prover === 'object' && 'publisher' in this.keystore.prover) {
|
|
127
|
+
collectRemoteSigners(this.keystore.prover.publisher, this.keystore.remoteSigner);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Validate each remote signer URL with all its addresses
|
|
131
|
+
for (const [url, addresses] of remoteSignersByUrl.entries()) {
|
|
132
|
+
if (addresses.size > 0) {
|
|
133
|
+
await RemoteSigner.validateAccess(url, Array.from(addresses));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
60
138
|
/**
|
|
61
139
|
* Validates that attester addresses are unique across all validators
|
|
62
140
|
* Only checks simple private key attesters, not JSON-V3 or mnemonic attesters,
|
|
@@ -85,67 +163,57 @@ export class KeystoreManager {
|
|
|
85
163
|
* Best-effort address extraction that avoids decryption/derivation (no JSON-V3 or mnemonic processing).
|
|
86
164
|
* This is used at construction time to check for obvious duplicates without throwing for invalid inputs.
|
|
87
165
|
*/
|
|
88
|
-
private extractAddressesWithoutSensitiveOperations(accounts:
|
|
166
|
+
private extractAddressesWithoutSensitiveOperations(accounts: AttesterAccounts): EthAddress[] {
|
|
167
|
+
const ethAccounts = this.extractEthAccountsFromAttester(accounts);
|
|
168
|
+
return this.extractAddressesFromEthAccountsNonSensitive(ethAccounts);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Extract addresses from EthAccounts without sensitive operations (no decryption/derivation).
|
|
173
|
+
*/
|
|
174
|
+
private extractAddressesFromEthAccountsNonSensitive(accounts: EthAccounts): EthAddress[] {
|
|
89
175
|
const results: EthAddress[] = [];
|
|
90
176
|
|
|
91
177
|
const handleAccount = (account: EthAccount): void => {
|
|
92
|
-
// String cases: private key or address or remote signer address
|
|
93
178
|
if (typeof account === 'string') {
|
|
94
179
|
if (account.startsWith('0x') && account.length === 66) {
|
|
95
|
-
// Private key -> derive address locally without external deps
|
|
96
180
|
try {
|
|
97
|
-
const signer = new LocalSigner(Buffer32.fromString(account
|
|
181
|
+
const signer = new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
|
|
98
182
|
results.push(signer.address);
|
|
99
183
|
} catch {
|
|
100
|
-
//
|
|
101
|
-
}
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (account.startsWith('0x') && account.length === 42) {
|
|
106
|
-
// Address string
|
|
107
|
-
try {
|
|
108
|
-
results.push(EthAddress.fromString(account));
|
|
109
|
-
} catch {
|
|
110
|
-
// Ignore invalid address format at construction time
|
|
184
|
+
// ignore invalid private key at construction time
|
|
111
185
|
}
|
|
112
|
-
return;
|
|
113
186
|
}
|
|
114
|
-
|
|
115
|
-
// Any other string cannot be confidently resolved here
|
|
116
187
|
return;
|
|
117
188
|
}
|
|
118
189
|
|
|
119
|
-
// JSON V3 keystore: skip (requires decryption)
|
|
120
190
|
if ('path' in account) {
|
|
121
191
|
return;
|
|
122
192
|
}
|
|
123
193
|
|
|
124
|
-
// Mnemonic: skip (requires derivation and may throw on invalid mnemonics)
|
|
125
194
|
if ('mnemonic' in (account as any)) {
|
|
126
195
|
return;
|
|
127
196
|
}
|
|
128
197
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
results.push(EthAddress.fromString(address));
|
|
135
|
-
} catch {
|
|
136
|
-
// Ignore invalid address format at construction time
|
|
137
|
-
}
|
|
198
|
+
const remoteSigner: EthRemoteSignerAccount = account;
|
|
199
|
+
if ('address' in remoteSigner) {
|
|
200
|
+
results.push(remoteSigner.address);
|
|
201
|
+
return;
|
|
138
202
|
}
|
|
203
|
+
results.push(remoteSigner);
|
|
139
204
|
};
|
|
140
205
|
|
|
141
206
|
if (Array.isArray(accounts)) {
|
|
142
207
|
for (const account of accounts) {
|
|
143
|
-
|
|
144
|
-
results.push(...subResults);
|
|
208
|
+
handleAccount(account as EthAccount);
|
|
145
209
|
}
|
|
146
210
|
return results;
|
|
147
211
|
}
|
|
148
212
|
|
|
213
|
+
if (typeof accounts === 'object' && accounts !== null && 'mnemonic' in (accounts as any)) {
|
|
214
|
+
return results;
|
|
215
|
+
}
|
|
216
|
+
|
|
149
217
|
handleAccount(accounts as EthAccount);
|
|
150
218
|
return results;
|
|
151
219
|
}
|
|
@@ -155,11 +223,12 @@ export class KeystoreManager {
|
|
|
155
223
|
*/
|
|
156
224
|
createAttesterSigners(validatorIndex: number): EthSigner[] {
|
|
157
225
|
const validator = this.getValidator(validatorIndex);
|
|
158
|
-
|
|
226
|
+
const ethAccounts = this.extractEthAccountsFromAttester(validator.attester);
|
|
227
|
+
return this.createSignersFromEthAccounts(ethAccounts, validator.remoteSigner || this.keystore.remoteSigner);
|
|
159
228
|
}
|
|
160
229
|
|
|
161
230
|
/**
|
|
162
|
-
* Create signers for validator publisher accounts (falls back to attester if not specified)
|
|
231
|
+
* Create signers for validator publisher accounts (falls back to keystore-level publisher, then to attester if not specified)
|
|
163
232
|
*/
|
|
164
233
|
createPublisherSigners(validatorIndex: number): EthSigner[] {
|
|
165
234
|
const validator = this.getValidator(validatorIndex);
|
|
@@ -171,6 +240,14 @@ export class KeystoreManager {
|
|
|
171
240
|
);
|
|
172
241
|
}
|
|
173
242
|
|
|
243
|
+
// Fall back to keystore-level publisher
|
|
244
|
+
if (this.keystore.publisher) {
|
|
245
|
+
return this.createSignersFromEthAccounts(
|
|
246
|
+
this.keystore.publisher,
|
|
247
|
+
validator.remoteSigner || this.keystore.remoteSigner,
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
174
251
|
// Fall back to attester signers
|
|
175
252
|
return this.createAttesterSigners(validatorIndex);
|
|
176
253
|
}
|
|
@@ -205,7 +282,7 @@ export class KeystoreManager {
|
|
|
205
282
|
return undefined;
|
|
206
283
|
}
|
|
207
284
|
|
|
208
|
-
// Handle
|
|
285
|
+
// Handle prover being a private key, JSON key store or remote signer with nested address
|
|
209
286
|
if (
|
|
210
287
|
typeof this.keystore.prover === 'string' ||
|
|
211
288
|
'path' in this.keystore.prover ||
|
|
@@ -218,10 +295,19 @@ export class KeystoreManager {
|
|
|
218
295
|
};
|
|
219
296
|
}
|
|
220
297
|
|
|
221
|
-
|
|
222
|
-
|
|
298
|
+
// Handle prover as Id and specified publishers
|
|
299
|
+
if ('id' in this.keystore.prover) {
|
|
300
|
+
const id = this.keystore.prover.id;
|
|
301
|
+
const signers = this.createSignersFromEthAccounts(this.keystore.prover.publisher, this.keystore.remoteSigner);
|
|
302
|
+
return { id, signers };
|
|
303
|
+
}
|
|
223
304
|
|
|
224
|
-
|
|
305
|
+
// Here, prover is just an EthAddress for a remote signer
|
|
306
|
+
const signers = this.createSignersFromEthAccounts(this.keystore.prover, this.keystore.remoteSigner);
|
|
307
|
+
return {
|
|
308
|
+
id: undefined,
|
|
309
|
+
signers,
|
|
310
|
+
};
|
|
225
311
|
}
|
|
226
312
|
|
|
227
313
|
/**
|
|
@@ -242,30 +328,42 @@ export class KeystoreManager {
|
|
|
242
328
|
}
|
|
243
329
|
|
|
244
330
|
/**
|
|
245
|
-
* Get coinbase address for validator (falls back to
|
|
331
|
+
* Get coinbase address for validator (falls back to keystore-level coinbase, then to the specific attester address)
|
|
246
332
|
*/
|
|
247
|
-
getCoinbaseAddress(validatorIndex: number): EthAddress {
|
|
333
|
+
getCoinbaseAddress(validatorIndex: number, attesterAddress: EthAddress): EthAddress {
|
|
248
334
|
const validator = this.getValidator(validatorIndex);
|
|
249
335
|
|
|
250
336
|
if (validator.coinbase) {
|
|
251
|
-
return
|
|
337
|
+
return validator.coinbase;
|
|
252
338
|
}
|
|
253
339
|
|
|
254
|
-
// Fall back to
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
throw new KeystoreError(`No attester signers found for validator ${validatorIndex}`);
|
|
340
|
+
// Fall back to keystore-level coinbase
|
|
341
|
+
if (this.keystore.coinbase) {
|
|
342
|
+
return this.keystore.coinbase;
|
|
258
343
|
}
|
|
259
344
|
|
|
260
|
-
|
|
345
|
+
// Fall back to the specific attester address
|
|
346
|
+
return attesterAddress;
|
|
261
347
|
}
|
|
262
348
|
|
|
263
349
|
/**
|
|
264
|
-
* Get fee recipient for validator
|
|
350
|
+
* Get fee recipient for validator (falls back to keystore-level feeRecipient)
|
|
265
351
|
*/
|
|
266
|
-
getFeeRecipient(validatorIndex: number):
|
|
352
|
+
getFeeRecipient(validatorIndex: number): AztecAddress {
|
|
267
353
|
const validator = this.getValidator(validatorIndex);
|
|
268
|
-
|
|
354
|
+
|
|
355
|
+
if (validator.feeRecipient) {
|
|
356
|
+
return validator.feeRecipient;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Fall back to keystore-level feeRecipient
|
|
360
|
+
if (this.keystore.feeRecipient) {
|
|
361
|
+
return this.keystore.feeRecipient;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
throw new KeystoreError(
|
|
365
|
+
`No feeRecipient configured for validator ${validatorIndex}. You can set it at validator or keystore level.`,
|
|
366
|
+
);
|
|
269
367
|
}
|
|
270
368
|
|
|
271
369
|
/**
|
|
@@ -294,7 +392,7 @@ export class KeystoreManager {
|
|
|
294
392
|
for (let validatorIndex = 0; validatorIndex < validatorCount; validatorIndex++) {
|
|
295
393
|
const validator = this.getValidator(validatorIndex);
|
|
296
394
|
const signers = this.createSignersFromEthAccounts(
|
|
297
|
-
validator.attester,
|
|
395
|
+
this.extractEthAccountsFromAttester(validator.attester),
|
|
298
396
|
validator.remoteSigner || this.keystore.remoteSigner,
|
|
299
397
|
);
|
|
300
398
|
for (const signer of signers) {
|
|
@@ -351,13 +449,9 @@ export class KeystoreManager {
|
|
|
351
449
|
if (typeof account === 'string') {
|
|
352
450
|
if (account.startsWith('0x') && account.length === 66) {
|
|
353
451
|
// Private key
|
|
354
|
-
return new LocalSigner(Buffer32.fromString(account
|
|
452
|
+
return new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
|
|
355
453
|
} else {
|
|
356
|
-
|
|
357
|
-
if (!defaultRemoteSigner) {
|
|
358
|
-
throw new KeystoreError(`No remote signer configuration found for address ${account}`);
|
|
359
|
-
}
|
|
360
|
-
return new RemoteSigner(EthAddress.fromString(account), defaultRemoteSigner);
|
|
454
|
+
throw new Error(`Invalid private key`);
|
|
361
455
|
}
|
|
362
456
|
}
|
|
363
457
|
|
|
@@ -368,35 +462,35 @@ export class KeystoreManager {
|
|
|
368
462
|
}
|
|
369
463
|
|
|
370
464
|
// Remote signer account
|
|
371
|
-
const remoteSigner = account
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
465
|
+
const remoteSigner: EthRemoteSignerAccount = account;
|
|
466
|
+
|
|
467
|
+
if ('address' in remoteSigner) {
|
|
468
|
+
// Remote signer with config
|
|
469
|
+
const config = remoteSigner.remoteSignerUrl
|
|
470
|
+
? {
|
|
471
|
+
remoteSignerUrl: remoteSigner.remoteSignerUrl,
|
|
472
|
+
certPath: remoteSigner.certPath,
|
|
473
|
+
certPass: remoteSigner.certPass,
|
|
474
|
+
}
|
|
475
|
+
: defaultRemoteSigner;
|
|
476
|
+
if (!config) {
|
|
477
|
+
throw new KeystoreError(`No remote signer configuration found for address ${remoteSigner.address}`);
|
|
376
478
|
}
|
|
377
|
-
return new RemoteSigner(EthAddress.fromString(remoteSigner), defaultRemoteSigner);
|
|
378
|
-
}
|
|
379
479
|
|
|
380
|
-
|
|
381
|
-
const config = remoteSigner.remoteSignerUrl
|
|
382
|
-
? {
|
|
383
|
-
remoteSignerUrl: remoteSigner.remoteSignerUrl,
|
|
384
|
-
certPath: remoteSigner.certPath,
|
|
385
|
-
certPass: remoteSigner.certPass,
|
|
386
|
-
}
|
|
387
|
-
: defaultRemoteSigner;
|
|
388
|
-
|
|
389
|
-
if (!config) {
|
|
390
|
-
throw new KeystoreError(`No remote signer configuration found for address ${remoteSigner.address}`);
|
|
480
|
+
return new RemoteSigner(remoteSigner.address, config);
|
|
391
481
|
}
|
|
392
482
|
|
|
393
|
-
|
|
483
|
+
// Just an address - use default config
|
|
484
|
+
if (!defaultRemoteSigner) {
|
|
485
|
+
throw new KeystoreError(`No remote signer configuration found for address ${remoteSigner}`);
|
|
486
|
+
}
|
|
487
|
+
return new RemoteSigner(remoteSigner, defaultRemoteSigner);
|
|
394
488
|
}
|
|
395
489
|
|
|
396
490
|
/**
|
|
397
491
|
* Create signer from JSON V3 keystore file or directory
|
|
398
492
|
*/
|
|
399
|
-
private createSignerFromJsonV3(config:
|
|
493
|
+
private createSignerFromJsonV3(config: EncryptedKeyFileConfig): EthSigner[] {
|
|
400
494
|
try {
|
|
401
495
|
const stats = statSync(config.path);
|
|
402
496
|
|
|
@@ -476,7 +570,7 @@ export class KeystoreManager {
|
|
|
476
570
|
/**
|
|
477
571
|
* Create signers from mnemonic configuration using BIP44 derivation
|
|
478
572
|
*/
|
|
479
|
-
private createSignersFromMnemonic(config:
|
|
573
|
+
private createSignersFromMnemonic(config: MnemonicConfig): EthSigner[] {
|
|
480
574
|
const { mnemonic, addressIndex = 0, accountIndex = 0, addressCount = 1, accountCount = 1 } = config;
|
|
481
575
|
const signers: EthSigner[] = [];
|
|
482
576
|
|
|
@@ -531,25 +625,18 @@ export class KeystoreManager {
|
|
|
531
625
|
const validator = this.getValidator(validatorIndex);
|
|
532
626
|
|
|
533
627
|
// Helper to get address from an account configuration
|
|
534
|
-
const getAddressFromAccount = (account: EthAccount): EthAddress | EthAddress[] |
|
|
628
|
+
const getAddressFromAccount = (account: EthAccount): EthAddress | EthAddress[] | undefined => {
|
|
535
629
|
if (typeof account === 'string') {
|
|
536
630
|
if (account.startsWith('0x') && account.length === 66) {
|
|
537
631
|
// This is a private key - derive the address
|
|
538
632
|
try {
|
|
539
|
-
const signer = new LocalSigner(Buffer32.fromString(account
|
|
633
|
+
const signer = new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
|
|
540
634
|
return signer.address;
|
|
541
635
|
} catch {
|
|
542
|
-
return
|
|
543
|
-
}
|
|
544
|
-
} else if (account.startsWith('0x') && account.length === 42) {
|
|
545
|
-
// This is an address
|
|
546
|
-
try {
|
|
547
|
-
return EthAddress.fromString(account);
|
|
548
|
-
} catch {
|
|
549
|
-
return null;
|
|
636
|
+
return undefined;
|
|
550
637
|
}
|
|
551
638
|
}
|
|
552
|
-
return
|
|
639
|
+
return undefined;
|
|
553
640
|
}
|
|
554
641
|
|
|
555
642
|
// JSON V3 keystore
|
|
@@ -558,18 +645,16 @@ export class KeystoreManager {
|
|
|
558
645
|
const signers = this.createSignerFromJsonV3(account);
|
|
559
646
|
return signers.map(s => s.address);
|
|
560
647
|
} catch {
|
|
561
|
-
return
|
|
648
|
+
return undefined;
|
|
562
649
|
}
|
|
563
650
|
}
|
|
564
651
|
|
|
565
|
-
// Remote signer account
|
|
566
|
-
const remoteSigner = account
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return EthAddress.fromString(address);
|
|
570
|
-
} catch {
|
|
571
|
-
return null;
|
|
652
|
+
// Remote signer account, either it is an address or the address is nested
|
|
653
|
+
const remoteSigner: EthRemoteSignerAccount = account;
|
|
654
|
+
if ('address' in remoteSigner) {
|
|
655
|
+
return remoteSigner.address;
|
|
572
656
|
}
|
|
657
|
+
return remoteSigner;
|
|
573
658
|
};
|
|
574
659
|
|
|
575
660
|
// Helper to check if account matches and get its remote signer config
|
|
@@ -588,13 +673,7 @@ export class KeystoreManager {
|
|
|
588
673
|
|
|
589
674
|
// Found a match - determine the config to return
|
|
590
675
|
if (typeof account === 'string') {
|
|
591
|
-
|
|
592
|
-
// Private key - local signer, no remote config
|
|
593
|
-
return undefined;
|
|
594
|
-
} else {
|
|
595
|
-
// Address only - use defaults
|
|
596
|
-
return validator.remoteSigner || this.keystore.remoteSigner;
|
|
597
|
-
}
|
|
676
|
+
return undefined;
|
|
598
677
|
}
|
|
599
678
|
|
|
600
679
|
// JSON V3 - local signer, no remote config
|
|
@@ -603,57 +682,75 @@ export class KeystoreManager {
|
|
|
603
682
|
}
|
|
604
683
|
|
|
605
684
|
// Remote signer account with potential override
|
|
606
|
-
const remoteSigner = account
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
685
|
+
const remoteSigner: EthRemoteSignerAccount = account;
|
|
686
|
+
|
|
687
|
+
if ('address' in remoteSigner) {
|
|
688
|
+
// Has inline config
|
|
689
|
+
if (remoteSigner.remoteSignerUrl) {
|
|
690
|
+
return {
|
|
691
|
+
remoteSignerUrl: remoteSigner.remoteSignerUrl,
|
|
692
|
+
certPath: remoteSigner.certPath,
|
|
693
|
+
certPass: remoteSigner.certPass,
|
|
694
|
+
};
|
|
695
|
+
} else {
|
|
696
|
+
// No URL specified, use defaults
|
|
697
|
+
return validator.remoteSigner || this.keystore.remoteSigner;
|
|
698
|
+
}
|
|
610
699
|
}
|
|
700
|
+
// Just an address, use defaults
|
|
701
|
+
return validator.remoteSigner || this.keystore.remoteSigner;
|
|
702
|
+
};
|
|
611
703
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
704
|
+
// Normalize attester to EthAccounts and search
|
|
705
|
+
const normalized = this.extractEthAccountsFromAttester(validator.attester);
|
|
706
|
+
|
|
707
|
+
const findInEthAccounts = (accs: EthAccounts): EthRemoteSignerConfig | undefined => {
|
|
708
|
+
if (typeof accs === 'string') {
|
|
709
|
+
return checkAccount(accs);
|
|
710
|
+
}
|
|
711
|
+
if (Array.isArray(accs)) {
|
|
712
|
+
for (const a of accs as EthAccount[]) {
|
|
713
|
+
const res = checkAccount(a);
|
|
714
|
+
if (res !== undefined) {
|
|
715
|
+
return res;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return undefined;
|
|
622
719
|
}
|
|
720
|
+
if (typeof accs === 'object' && accs !== null && 'mnemonic' in accs) {
|
|
721
|
+
// mnemonic-derived keys are local signers; no remote signer config
|
|
722
|
+
return undefined;
|
|
723
|
+
}
|
|
724
|
+
return checkAccount(accs as EthAccount);
|
|
623
725
|
};
|
|
624
726
|
|
|
625
|
-
|
|
626
|
-
|
|
727
|
+
return findInEthAccounts(normalized);
|
|
728
|
+
}
|
|
627
729
|
|
|
730
|
+
/** Extract ETH accounts from AttesterAccounts */
|
|
731
|
+
private extractEthAccountsFromAttester(attester: AttesterAccounts): EthAccounts {
|
|
628
732
|
if (typeof attester === 'string') {
|
|
629
|
-
|
|
630
|
-
return result === undefined ? undefined : result;
|
|
733
|
+
return attester;
|
|
631
734
|
}
|
|
632
|
-
|
|
633
735
|
if (Array.isArray(attester)) {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
if (
|
|
637
|
-
|
|
736
|
+
const out: EthAccount[] = [];
|
|
737
|
+
for (const item of attester) {
|
|
738
|
+
if (typeof item === 'string') {
|
|
739
|
+
out.push(item);
|
|
740
|
+
} else if ('eth' in (item as any)) {
|
|
741
|
+
out.push((item as any).eth as EthAccount);
|
|
742
|
+
} else if (!('mnemonic' in (item as any))) {
|
|
743
|
+
out.push(item as EthAccount);
|
|
638
744
|
}
|
|
639
745
|
}
|
|
640
|
-
return
|
|
746
|
+
return out;
|
|
641
747
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
if ('mnemonic' in attester) {
|
|
645
|
-
try {
|
|
646
|
-
const signers = this.createSignersFromMnemonic(attester);
|
|
647
|
-
const matches = signers.some(s => s.address.equals(attesterAddress));
|
|
648
|
-
// Mnemonic-derived keys are local signers
|
|
649
|
-
return matches ? undefined : undefined;
|
|
650
|
-
} catch {
|
|
651
|
-
return undefined;
|
|
652
|
-
}
|
|
748
|
+
if ('mnemonic' in (attester as any)) {
|
|
749
|
+
return attester as any;
|
|
653
750
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
return
|
|
751
|
+
if ('eth' in (attester as any)) {
|
|
752
|
+
return (attester as any).eth as EthAccount;
|
|
753
|
+
}
|
|
754
|
+
return attester as any;
|
|
658
755
|
}
|
|
659
756
|
}
|