@aztec/node-keystore 4.0.0-nightly.20250907 → 4.0.0-nightly.20260108

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.
@@ -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: EthAccounts): EthAddress[] {
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 as EthPrivateKey));
181
+ const signer = new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
98
182
  results.push(signer.address);
99
183
  } catch {
100
- // Ignore invalid private key at construction time
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
- // Remote signer account (object form)
130
- const remoteSigner = account as EthRemoteSignerAccount;
131
- const address = typeof remoteSigner === 'string' ? remoteSigner : remoteSigner.address;
132
- if (address) {
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
- const subResults = this.extractAddressesWithoutSensitiveOperations(account);
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
- return this.createSignersFromEthAccounts(validator.attester, validator.remoteSigner || this.keystore.remoteSigner);
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 simple prover case (just a private key)
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
- const id = EthAddress.fromString(this.keystore.prover.id);
222
- const signers = this.createSignersFromEthAccounts(this.keystore.prover.publisher, this.keystore.remoteSigner);
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
- return { id, signers };
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 first attester address)
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 EthAddress.fromString(validator.coinbase);
337
+ return validator.coinbase;
252
338
  }
253
339
 
254
- // Fall back to first attester address
255
- const attesterSigners = this.createAttesterSigners(validatorIndex);
256
- if (attesterSigners.length === 0) {
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
- return attesterSigners[0].address;
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): string {
352
+ getFeeRecipient(validatorIndex: number): AztecAddress {
267
353
  const validator = this.getValidator(validatorIndex);
268
- return validator.feeRecipient;
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 as EthPrivateKey));
452
+ return new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
355
453
  } else {
356
- // Remote signer address only - use default remote signer config
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 as EthRemoteSignerAccount;
372
- if (typeof remoteSigner === 'string') {
373
- // Just an address - use default config
374
- if (!defaultRemoteSigner) {
375
- throw new KeystoreError(`No remote signer configuration found for address ${remoteSigner}`);
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
- // Remote signer with config
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
- return new RemoteSigner(EthAddress.fromString(remoteSigner.address), config);
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: EthJsonKeyFileV3Config): EthSigner[] {
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: EthMnemonicConfig): EthSigner[] {
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[] | null => {
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 as EthPrivateKey));
633
+ const signer = new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
540
634
  return signer.address;
541
635
  } catch {
542
- return null;
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 null;
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 null;
648
+ return undefined;
562
649
  }
563
650
  }
564
651
 
565
- // Remote signer account
566
- const remoteSigner = account as EthRemoteSignerAccount;
567
- const address = typeof remoteSigner === 'string' ? remoteSigner : remoteSigner.address;
568
- try {
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
- if (account.startsWith('0x') && account.length === 66) {
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 as EthRemoteSignerAccount;
607
- if (typeof remoteSigner === 'string') {
608
- // Just an address - use defaults
609
- return validator.remoteSigner || this.keystore.remoteSigner;
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
- // Has inline config
613
- if (remoteSigner.remoteSignerUrl) {
614
- return {
615
- remoteSignerUrl: remoteSigner.remoteSignerUrl,
616
- certPath: remoteSigner.certPath,
617
- certPass: remoteSigner.certPass,
618
- };
619
- } else {
620
- // No URL specified, use defaults
621
- return validator.remoteSigner || this.keystore.remoteSigner;
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
- // Check the attester configuration
626
- const { attester } = validator;
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
- const result = checkAccount(attester);
630
- return result === undefined ? undefined : result;
733
+ return attester;
631
734
  }
632
-
633
735
  if (Array.isArray(attester)) {
634
- for (const account of attester) {
635
- const result = checkAccount(account);
636
- if (result !== undefined) {
637
- return result;
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 undefined;
746
+ return out;
641
747
  }
642
-
643
- // Mnemonic configuration
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
- // Single account object
656
- const result = checkAccount(attester);
657
- return result === undefined ? undefined : result;
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
  }