@aztec/node-keystore 2.0.0-rc.8 → 2.0.2-rc.1
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 +2 -1
- package/dest/keystore_manager.d.ts.map +1 -1
- package/dest/keystore_manager.js +60 -82
- package/dest/schemas.d.ts +563 -903
- package/dest/schemas.d.ts.map +1 -1
- package/dest/schemas.js +24 -26
- package/dest/types.d.ts +10 -11
- package/dest/types.d.ts.map +1 -1
- package/dest/types.js +1 -1
- package/package.json +4 -4
- package/src/keystore_manager.ts +73 -94
- package/src/loader.ts +1 -1
- package/src/schemas.ts +27 -33
- package/src/types.ts +14 -18
package/dest/schemas.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,eAAO,MAAM,mBAAmB,kDAGK,CAAC;AAiEtC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYvB,CAAC"}
|
package/dest/schemas.js
CHANGED
|
@@ -1,36 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Zod schemas for keystore validation using Aztec's validation functions
|
|
3
|
-
*/ import {
|
|
3
|
+
*/ import { optional, schemas } from '@aztec/foundation/schemas';
|
|
4
4
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
// Use Aztec's validation functions but return string types to match our TypeScript interfaces
|
|
7
|
-
const
|
|
8
|
-
const ethPrivateKeySchema = z.string().regex(/^0x[0-9a-fA-F]{64}$/, 'Invalid private key (must be 32 bytes with 0x prefix)');
|
|
9
|
-
const aztecAddressSchema = z.string().refine(AztecAddress.isAddress, 'Invalid Aztec address');
|
|
7
|
+
export const ethPrivateKeySchema = z.string().regex(/^0x[0-9a-fA-F]{64}$/, 'Invalid private key (must be 32 bytes with 0x prefix)').transform((s)=>s);
|
|
10
8
|
const urlSchema = z.string().url('Invalid URL');
|
|
11
9
|
// Remote signer config schema
|
|
12
10
|
const remoteSignerConfigSchema = z.union([
|
|
13
11
|
urlSchema,
|
|
14
12
|
z.object({
|
|
15
13
|
remoteSignerUrl: urlSchema,
|
|
16
|
-
certPath: z.string()
|
|
17
|
-
certPass: z.string()
|
|
14
|
+
certPath: optional(z.string()),
|
|
15
|
+
certPass: optional(z.string())
|
|
18
16
|
})
|
|
19
17
|
]);
|
|
20
18
|
// Remote signer account schema
|
|
21
19
|
const remoteSignerAccountSchema = z.union([
|
|
22
|
-
|
|
20
|
+
schemas.EthAddress,
|
|
23
21
|
z.object({
|
|
24
|
-
address:
|
|
25
|
-
remoteSignerUrl: urlSchema
|
|
26
|
-
certPath: z.string()
|
|
27
|
-
certPass: z.string()
|
|
22
|
+
address: schemas.EthAddress,
|
|
23
|
+
remoteSignerUrl: optional(urlSchema),
|
|
24
|
+
certPath: optional(z.string()),
|
|
25
|
+
certPass: optional(z.string())
|
|
28
26
|
})
|
|
29
27
|
]);
|
|
30
28
|
// JSON V3 keystore schema
|
|
31
29
|
const jsonKeyFileV3Schema = z.object({
|
|
32
30
|
path: z.string(),
|
|
33
|
-
password: z.string()
|
|
31
|
+
password: optional(z.string())
|
|
34
32
|
});
|
|
35
33
|
// Mnemonic config schema
|
|
36
34
|
const mnemonicConfigSchema = z.object({
|
|
@@ -44,39 +42,39 @@ const mnemonicConfigSchema = z.object({
|
|
|
44
42
|
const ethAccountSchema = z.union([
|
|
45
43
|
ethPrivateKeySchema,
|
|
46
44
|
remoteSignerAccountSchema,
|
|
47
|
-
jsonKeyFileV3Schema
|
|
48
|
-
mnemonicConfigSchema
|
|
45
|
+
jsonKeyFileV3Schema
|
|
49
46
|
]);
|
|
50
47
|
// EthAccounts schema
|
|
51
48
|
const ethAccountsSchema = z.union([
|
|
52
49
|
ethAccountSchema,
|
|
53
|
-
z.array(ethAccountSchema)
|
|
50
|
+
z.array(ethAccountSchema),
|
|
51
|
+
mnemonicConfigSchema
|
|
54
52
|
]);
|
|
55
53
|
// Prover keystore schema
|
|
56
54
|
const proverKeyStoreSchema = z.union([
|
|
57
55
|
ethAccountSchema,
|
|
58
56
|
z.object({
|
|
59
|
-
id:
|
|
57
|
+
id: schemas.EthAddress,
|
|
60
58
|
publisher: ethAccountsSchema
|
|
61
59
|
})
|
|
62
60
|
]);
|
|
63
61
|
// Validator keystore schema
|
|
64
62
|
const validatorKeyStoreSchema = z.object({
|
|
65
63
|
attester: ethAccountsSchema,
|
|
66
|
-
coinbase:
|
|
67
|
-
publisher: ethAccountsSchema
|
|
68
|
-
feeRecipient:
|
|
69
|
-
remoteSigner: remoteSignerConfigSchema
|
|
70
|
-
fundingAccount: ethAccountSchema
|
|
64
|
+
coinbase: optional(schemas.EthAddress),
|
|
65
|
+
publisher: optional(ethAccountsSchema),
|
|
66
|
+
feeRecipient: AztecAddress.schema,
|
|
67
|
+
remoteSigner: optional(remoteSignerConfigSchema),
|
|
68
|
+
fundingAccount: optional(ethAccountSchema)
|
|
71
69
|
});
|
|
72
70
|
// Main keystore schema
|
|
73
71
|
export const keystoreSchema = z.object({
|
|
74
72
|
schemaVersion: z.literal(1),
|
|
75
|
-
validators: z.array(validatorKeyStoreSchema)
|
|
76
|
-
slasher: ethAccountsSchema
|
|
77
|
-
remoteSigner: remoteSignerConfigSchema
|
|
78
|
-
prover: proverKeyStoreSchema
|
|
79
|
-
fundingAccount: ethAccountSchema
|
|
73
|
+
validators: optional(z.array(validatorKeyStoreSchema)),
|
|
74
|
+
slasher: optional(ethAccountsSchema),
|
|
75
|
+
remoteSigner: optional(remoteSignerConfigSchema),
|
|
76
|
+
prover: optional(proverKeyStoreSchema),
|
|
77
|
+
fundingAccount: optional(ethAccountSchema)
|
|
80
78
|
}).refine((data)=>data.validators || data.prover, {
|
|
81
79
|
message: 'Keystore must have at least validators or prover configuration',
|
|
82
80
|
path: [
|
package/dest/types.d.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* These types define the JSON structure for configuring validators, provers, and
|
|
6
6
|
* their associated keys and addresses.
|
|
7
7
|
*/
|
|
8
|
+
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
8
10
|
/** Parameterized hex string type for specific byte lengths */
|
|
9
11
|
export type Hex<TByteLength extends number> = `0x${string}` & {
|
|
10
12
|
readonly _length: TByteLength;
|
|
@@ -16,10 +18,6 @@ export type EthJsonKeyFileV3Config = {
|
|
|
16
18
|
};
|
|
17
19
|
/** A private key is a 32-byte 0x-prefixed hex */
|
|
18
20
|
export type EthPrivateKey = Hex<32>;
|
|
19
|
-
/** An address is a 20-byte 0x-prefixed hex */
|
|
20
|
-
export type EthAddressHex = Hex<20>;
|
|
21
|
-
/** An Aztec address is a 32-byte 0x-prefixed hex */
|
|
22
|
-
export type AztecAddressHex = Hex<32>;
|
|
23
21
|
/** URL type for remote signers */
|
|
24
22
|
export type Url = string;
|
|
25
23
|
/**
|
|
@@ -34,8 +32,8 @@ export type EthRemoteSignerConfig = Url | {
|
|
|
34
32
|
* A remote signer account config is equal to the remote signer config, but requires an address to be specified.
|
|
35
33
|
* If only the address is set, then the default remote signer config from the parent config is used.
|
|
36
34
|
*/
|
|
37
|
-
export type EthRemoteSignerAccount =
|
|
38
|
-
address:
|
|
35
|
+
export type EthRemoteSignerAccount = EthAddress | {
|
|
36
|
+
address: EthAddress;
|
|
39
37
|
remoteSignerUrl?: Url;
|
|
40
38
|
certPath?: string;
|
|
41
39
|
certPass?: string;
|
|
@@ -52,12 +50,13 @@ export type EthMnemonicConfig = {
|
|
|
52
50
|
};
|
|
53
51
|
/** One or more L1 accounts */
|
|
54
52
|
export type EthAccounts = EthAccount | EthAccount[] | EthMnemonicConfig;
|
|
55
|
-
export type
|
|
53
|
+
export type ProverKeyStoreWithId = {
|
|
56
54
|
/** Address that identifies the prover. This address will receive the rewards. */
|
|
57
|
-
id:
|
|
55
|
+
id: EthAddress;
|
|
58
56
|
/** One or more EOAs used for sending proof L1 txs. */
|
|
59
57
|
publisher: EthAccounts;
|
|
60
|
-
}
|
|
58
|
+
};
|
|
59
|
+
export type ProverKeyStore = ProverKeyStoreWithId | EthAccount;
|
|
61
60
|
export type ValidatorKeyStore = {
|
|
62
61
|
/**
|
|
63
62
|
* One or more validator attester keys to handle in this configuration block.
|
|
@@ -68,7 +67,7 @@ export type ValidatorKeyStore = {
|
|
|
68
67
|
* Coinbase address to use when proposing an L2 block as any of the validators in this configuration block.
|
|
69
68
|
* Falls back to the attester address if not set.
|
|
70
69
|
*/
|
|
71
|
-
coinbase?:
|
|
70
|
+
coinbase?: EthAddress;
|
|
72
71
|
/**
|
|
73
72
|
* One or more EOAs used for sending block proposal L1 txs for all validators in this configuration block.
|
|
74
73
|
* Falls back to the attester account if not set.
|
|
@@ -77,7 +76,7 @@ export type ValidatorKeyStore = {
|
|
|
77
76
|
/**
|
|
78
77
|
* Fee recipient address to use when proposing an L2 block as any of the validators in this configuration block.
|
|
79
78
|
*/
|
|
80
|
-
feeRecipient:
|
|
79
|
+
feeRecipient: AztecAddress;
|
|
81
80
|
/**
|
|
82
81
|
* Default remote signer for all accounts in this block.
|
|
83
82
|
*/
|
package/dest/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,8DAA8D;AAC9D,MAAM,MAAM,GAAG,CAAC,WAAW,SAAS,MAAM,IAAI,KAAK,MAAM,EAAE,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAEhG,iIAAiI;AACjI,MAAM,MAAM,sBAAsB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,iDAAiD;AACjD,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC;AAEpC,kCAAkC;AAClC,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC;AAEzB;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAC7B,GAAG,GACH;IACE,eAAe,EAAE,GAAG,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEN;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAC9B,UAAU,GACV;IACE,OAAO,EAAE,UAAU,CAAC;IACpB,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEN,uGAAuG;AACvG,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,sBAAsB,GAAG,sBAAsB,CAAC;AAEzF,yDAAyD;AACzD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,8BAA8B;AAC9B,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,UAAU,EAAE,GAAG,iBAAiB,CAAC;AAExE,MAAM,MAAM,oBAAoB,GAAG;IACjC,iFAAiF;IACjF,EAAE,EAAE,UAAU,CAAC;IACf,sDAAsD;IACtD,SAAS,EAAE,WAAW,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,UAAU,CAAC;AAE/D,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,QAAQ,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB;;;OAGG;IACH,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC;IAC3B;;OAEG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC;;OAEG;IACH,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,8GAA8G;IAC9G,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,sEAAsE;IACtE,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,wHAAwH;IACxH,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B,CAAC"}
|
package/dest/types.js
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* TypeScript definitions based on the specification for validator keystore files.
|
|
5
5
|
* These types define the JSON structure for configuring validators, provers, and
|
|
6
6
|
* their associated keys and addresses.
|
|
7
|
-
*/
|
|
7
|
+
*/ export { };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/node-keystore",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2-rc.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -62,9 +62,9 @@
|
|
|
62
62
|
]
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@aztec/ethereum": "2.0.
|
|
66
|
-
"@aztec/foundation": "2.0.
|
|
67
|
-
"@aztec/stdlib": "2.0.
|
|
65
|
+
"@aztec/ethereum": "2.0.2-rc.1",
|
|
66
|
+
"@aztec/foundation": "2.0.2-rc.1",
|
|
67
|
+
"@aztec/stdlib": "2.0.2-rc.1",
|
|
68
68
|
"@ethersproject/wallet": "^5.7.0",
|
|
69
69
|
"tslib": "^2.4.0",
|
|
70
70
|
"viem": "2.23.7",
|
package/src/keystore_manager.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { EthSigner } from '@aztec/ethereum';
|
|
|
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,13 +15,13 @@ 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 {
|
|
19
21
|
EthAccount,
|
|
20
22
|
EthAccounts,
|
|
21
23
|
EthJsonKeyFileV3Config,
|
|
22
24
|
EthMnemonicConfig,
|
|
23
|
-
EthPrivateKey,
|
|
24
25
|
EthRemoteSignerAccount,
|
|
25
26
|
EthRemoteSignerConfig,
|
|
26
27
|
KeyStore,
|
|
@@ -94,7 +95,7 @@ export class KeystoreManager {
|
|
|
94
95
|
if (account.startsWith('0x') && account.length === 66) {
|
|
95
96
|
// Private key -> derive address locally without external deps
|
|
96
97
|
try {
|
|
97
|
-
const signer = new LocalSigner(Buffer32.fromString(account
|
|
98
|
+
const signer = new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
|
|
98
99
|
results.push(signer.address);
|
|
99
100
|
} catch {
|
|
100
101
|
// Ignore invalid private key at construction time
|
|
@@ -102,16 +103,6 @@ export class KeystoreManager {
|
|
|
102
103
|
return;
|
|
103
104
|
}
|
|
104
105
|
|
|
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
|
|
111
|
-
}
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
106
|
// Any other string cannot be confidently resolved here
|
|
116
107
|
return;
|
|
117
108
|
}
|
|
@@ -126,16 +117,13 @@ export class KeystoreManager {
|
|
|
126
117
|
return;
|
|
127
118
|
}
|
|
128
119
|
|
|
129
|
-
// Remote signer account
|
|
130
|
-
const remoteSigner = account
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
results.push(EthAddress.fromString(address));
|
|
135
|
-
} catch {
|
|
136
|
-
// Ignore invalid address format at construction time
|
|
137
|
-
}
|
|
120
|
+
// Remote signer account. If it contains 'address' then extract, otherwise it IS the address
|
|
121
|
+
const remoteSigner: EthRemoteSignerAccount = account;
|
|
122
|
+
if ('address' in remoteSigner) {
|
|
123
|
+
results.push(remoteSigner.address);
|
|
124
|
+
return;
|
|
138
125
|
}
|
|
126
|
+
results.push(remoteSigner);
|
|
139
127
|
};
|
|
140
128
|
|
|
141
129
|
if (Array.isArray(accounts)) {
|
|
@@ -205,7 +193,7 @@ export class KeystoreManager {
|
|
|
205
193
|
return undefined;
|
|
206
194
|
}
|
|
207
195
|
|
|
208
|
-
// Handle
|
|
196
|
+
// Handle prover being a private key, JSON key store or remote signer with nested address
|
|
209
197
|
if (
|
|
210
198
|
typeof this.keystore.prover === 'string' ||
|
|
211
199
|
'path' in this.keystore.prover ||
|
|
@@ -218,10 +206,20 @@ export class KeystoreManager {
|
|
|
218
206
|
};
|
|
219
207
|
}
|
|
220
208
|
|
|
221
|
-
|
|
222
|
-
|
|
209
|
+
// Handle prover as Id and specified publishers
|
|
210
|
+
if ('id' in this.keystore.prover) {
|
|
211
|
+
const id = this.keystore.prover.id;
|
|
212
|
+
const signers = this.createSignersFromEthAccounts(this.keystore.prover.publisher, this.keystore.remoteSigner);
|
|
223
213
|
|
|
224
|
-
|
|
214
|
+
return { id, signers };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Here, prover is just an EthAddress for a remote signer
|
|
218
|
+
const signers = this.createSignersFromEthAccounts(this.keystore.prover, this.keystore.remoteSigner);
|
|
219
|
+
return {
|
|
220
|
+
id: undefined,
|
|
221
|
+
signers,
|
|
222
|
+
};
|
|
225
223
|
}
|
|
226
224
|
|
|
227
225
|
/**
|
|
@@ -248,7 +246,7 @@ export class KeystoreManager {
|
|
|
248
246
|
const validator = this.getValidator(validatorIndex);
|
|
249
247
|
|
|
250
248
|
if (validator.coinbase) {
|
|
251
|
-
return
|
|
249
|
+
return validator.coinbase;
|
|
252
250
|
}
|
|
253
251
|
|
|
254
252
|
// Fall back to first attester address
|
|
@@ -263,7 +261,7 @@ export class KeystoreManager {
|
|
|
263
261
|
/**
|
|
264
262
|
* Get fee recipient for validator
|
|
265
263
|
*/
|
|
266
|
-
getFeeRecipient(validatorIndex: number):
|
|
264
|
+
getFeeRecipient(validatorIndex: number): AztecAddress {
|
|
267
265
|
const validator = this.getValidator(validatorIndex);
|
|
268
266
|
return validator.feeRecipient;
|
|
269
267
|
}
|
|
@@ -351,13 +349,9 @@ export class KeystoreManager {
|
|
|
351
349
|
if (typeof account === 'string') {
|
|
352
350
|
if (account.startsWith('0x') && account.length === 66) {
|
|
353
351
|
// Private key
|
|
354
|
-
return new LocalSigner(Buffer32.fromString(account
|
|
352
|
+
return new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
|
|
355
353
|
} 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);
|
|
354
|
+
throw new Error(`Invalid private key`);
|
|
361
355
|
}
|
|
362
356
|
}
|
|
363
357
|
|
|
@@ -368,29 +362,29 @@ export class KeystoreManager {
|
|
|
368
362
|
}
|
|
369
363
|
|
|
370
364
|
// Remote signer account
|
|
371
|
-
const remoteSigner = account
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
365
|
+
const remoteSigner: EthRemoteSignerAccount = account;
|
|
366
|
+
|
|
367
|
+
if ('address' in remoteSigner) {
|
|
368
|
+
// Remote signer with config
|
|
369
|
+
const config = remoteSigner.remoteSignerUrl
|
|
370
|
+
? {
|
|
371
|
+
remoteSignerUrl: remoteSigner.remoteSignerUrl,
|
|
372
|
+
certPath: remoteSigner.certPath,
|
|
373
|
+
certPass: remoteSigner.certPass,
|
|
374
|
+
}
|
|
375
|
+
: defaultRemoteSigner;
|
|
376
|
+
if (!config) {
|
|
377
|
+
throw new KeystoreError(`No remote signer configuration found for address ${remoteSigner.address}`);
|
|
376
378
|
}
|
|
377
|
-
return new RemoteSigner(EthAddress.fromString(remoteSigner), defaultRemoteSigner);
|
|
378
|
-
}
|
|
379
|
-
|
|
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
379
|
|
|
389
|
-
|
|
390
|
-
throw new KeystoreError(`No remote signer configuration found for address ${remoteSigner.address}`);
|
|
380
|
+
return new RemoteSigner(remoteSigner.address, config);
|
|
391
381
|
}
|
|
392
382
|
|
|
393
|
-
|
|
383
|
+
// Just an address - use default config
|
|
384
|
+
if (!defaultRemoteSigner) {
|
|
385
|
+
throw new KeystoreError(`No remote signer configuration found for address ${remoteSigner}`);
|
|
386
|
+
}
|
|
387
|
+
return new RemoteSigner(remoteSigner, defaultRemoteSigner);
|
|
394
388
|
}
|
|
395
389
|
|
|
396
390
|
/**
|
|
@@ -531,25 +525,18 @@ export class KeystoreManager {
|
|
|
531
525
|
const validator = this.getValidator(validatorIndex);
|
|
532
526
|
|
|
533
527
|
// Helper to get address from an account configuration
|
|
534
|
-
const getAddressFromAccount = (account: EthAccount): EthAddress | EthAddress[] |
|
|
528
|
+
const getAddressFromAccount = (account: EthAccount): EthAddress | EthAddress[] | undefined => {
|
|
535
529
|
if (typeof account === 'string') {
|
|
536
530
|
if (account.startsWith('0x') && account.length === 66) {
|
|
537
531
|
// This is a private key - derive the address
|
|
538
532
|
try {
|
|
539
|
-
const signer = new LocalSigner(Buffer32.fromString(account
|
|
533
|
+
const signer = new LocalSigner(Buffer32.fromString(ethPrivateKeySchema.parse(account)));
|
|
540
534
|
return signer.address;
|
|
541
535
|
} 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;
|
|
536
|
+
return undefined;
|
|
550
537
|
}
|
|
551
538
|
}
|
|
552
|
-
return
|
|
539
|
+
return undefined;
|
|
553
540
|
}
|
|
554
541
|
|
|
555
542
|
// JSON V3 keystore
|
|
@@ -558,18 +545,16 @@ export class KeystoreManager {
|
|
|
558
545
|
const signers = this.createSignerFromJsonV3(account);
|
|
559
546
|
return signers.map(s => s.address);
|
|
560
547
|
} catch {
|
|
561
|
-
return
|
|
548
|
+
return undefined;
|
|
562
549
|
}
|
|
563
550
|
}
|
|
564
551
|
|
|
565
|
-
// Remote signer account
|
|
566
|
-
const remoteSigner = account
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return EthAddress.fromString(address);
|
|
570
|
-
} catch {
|
|
571
|
-
return null;
|
|
552
|
+
// Remote signer account, either it is an address or the address is nested
|
|
553
|
+
const remoteSigner: EthRemoteSignerAccount = account;
|
|
554
|
+
if ('address' in remoteSigner) {
|
|
555
|
+
return remoteSigner.address;
|
|
572
556
|
}
|
|
557
|
+
return remoteSigner;
|
|
573
558
|
};
|
|
574
559
|
|
|
575
560
|
// Helper to check if account matches and get its remote signer config
|
|
@@ -588,13 +573,7 @@ export class KeystoreManager {
|
|
|
588
573
|
|
|
589
574
|
// Found a match - determine the config to return
|
|
590
575
|
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
|
-
}
|
|
576
|
+
return undefined;
|
|
598
577
|
}
|
|
599
578
|
|
|
600
579
|
// JSON V3 - local signer, no remote config
|
|
@@ -603,23 +582,23 @@ export class KeystoreManager {
|
|
|
603
582
|
}
|
|
604
583
|
|
|
605
584
|
// Remote signer account with potential override
|
|
606
|
-
const remoteSigner = account
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
// No URL specified, use defaults
|
|
621
|
-
return validator.remoteSigner || this.keystore.remoteSigner;
|
|
585
|
+
const remoteSigner: EthRemoteSignerAccount = account;
|
|
586
|
+
|
|
587
|
+
if ('address' in remoteSigner) {
|
|
588
|
+
// Has inline config
|
|
589
|
+
if (remoteSigner.remoteSignerUrl) {
|
|
590
|
+
return {
|
|
591
|
+
remoteSignerUrl: remoteSigner.remoteSignerUrl,
|
|
592
|
+
certPath: remoteSigner.certPath,
|
|
593
|
+
certPass: remoteSigner.certPass,
|
|
594
|
+
};
|
|
595
|
+
} else {
|
|
596
|
+
// No URL specified, use defaults
|
|
597
|
+
return validator.remoteSigner || this.keystore.remoteSigner;
|
|
598
|
+
}
|
|
622
599
|
}
|
|
600
|
+
// Just an address, use defaults
|
|
601
|
+
return validator.remoteSigner || this.keystore.remoteSigner;
|
|
623
602
|
};
|
|
624
603
|
|
|
625
604
|
// Check the attester configuration
|
package/src/loader.ts
CHANGED
|
@@ -39,7 +39,7 @@ export function loadKeystoreFile(filePath: string): KeyStore {
|
|
|
39
39
|
const content = readFileSync(filePath, 'utf-8');
|
|
40
40
|
|
|
41
41
|
// Parse JSON and validate with Zod schema (following Aztec patterns)
|
|
42
|
-
return keystoreSchema.parse(JSON.parse(content))
|
|
42
|
+
return keystoreSchema.parse(JSON.parse(content));
|
|
43
43
|
} catch (error) {
|
|
44
44
|
if (error instanceof SyntaxError) {
|
|
45
45
|
throw new KeyStoreLoadError('Invalid JSON format', filePath, error);
|
package/src/schemas.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Zod schemas for keystore validation using Aztec's validation functions
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { optional, schemas } from '@aztec/foundation/schemas';
|
|
5
5
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
6
6
|
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
|
|
9
|
+
import type { EthPrivateKey } from './types.js';
|
|
10
|
+
|
|
9
11
|
// Use Aztec's validation functions but return string types to match our TypeScript interfaces
|
|
10
|
-
const
|
|
11
|
-
const ethPrivateKeySchema = z
|
|
12
|
+
export const ethPrivateKeySchema = z
|
|
12
13
|
.string()
|
|
13
|
-
.regex(/^0x[0-9a-fA-F]{64}$/, 'Invalid private key (must be 32 bytes with 0x prefix)')
|
|
14
|
-
|
|
14
|
+
.regex(/^0x[0-9a-fA-F]{64}$/, 'Invalid private key (must be 32 bytes with 0x prefix)')
|
|
15
|
+
.transform(s => s as EthPrivateKey);
|
|
15
16
|
const urlSchema = z.string().url('Invalid URL');
|
|
16
17
|
|
|
17
18
|
// Remote signer config schema
|
|
@@ -19,26 +20,26 @@ const remoteSignerConfigSchema = z.union([
|
|
|
19
20
|
urlSchema,
|
|
20
21
|
z.object({
|
|
21
22
|
remoteSignerUrl: urlSchema,
|
|
22
|
-
certPath: z.string()
|
|
23
|
-
certPass: z.string()
|
|
23
|
+
certPath: optional(z.string()),
|
|
24
|
+
certPass: optional(z.string()),
|
|
24
25
|
}),
|
|
25
26
|
]);
|
|
26
27
|
|
|
27
28
|
// Remote signer account schema
|
|
28
29
|
const remoteSignerAccountSchema = z.union([
|
|
29
|
-
|
|
30
|
+
schemas.EthAddress,
|
|
30
31
|
z.object({
|
|
31
|
-
address:
|
|
32
|
-
remoteSignerUrl: urlSchema
|
|
33
|
-
certPath: z.string()
|
|
34
|
-
certPass: z.string()
|
|
32
|
+
address: schemas.EthAddress,
|
|
33
|
+
remoteSignerUrl: optional(urlSchema),
|
|
34
|
+
certPath: optional(z.string()),
|
|
35
|
+
certPass: optional(z.string()),
|
|
35
36
|
}),
|
|
36
37
|
]);
|
|
37
38
|
|
|
38
39
|
// JSON V3 keystore schema
|
|
39
40
|
const jsonKeyFileV3Schema = z.object({
|
|
40
41
|
path: z.string(),
|
|
41
|
-
password: z.string()
|
|
42
|
+
password: optional(z.string()),
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
// Mnemonic config schema
|
|
@@ -51,21 +52,16 @@ const mnemonicConfigSchema = z.object({
|
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
// EthAccount schema
|
|
54
|
-
const ethAccountSchema = z.union([
|
|
55
|
-
ethPrivateKeySchema,
|
|
56
|
-
remoteSignerAccountSchema,
|
|
57
|
-
jsonKeyFileV3Schema,
|
|
58
|
-
mnemonicConfigSchema,
|
|
59
|
-
]);
|
|
55
|
+
const ethAccountSchema = z.union([ethPrivateKeySchema, remoteSignerAccountSchema, jsonKeyFileV3Schema]);
|
|
60
56
|
|
|
61
57
|
// EthAccounts schema
|
|
62
|
-
const ethAccountsSchema = z.union([ethAccountSchema, z.array(ethAccountSchema)]);
|
|
58
|
+
const ethAccountsSchema = z.union([ethAccountSchema, z.array(ethAccountSchema), mnemonicConfigSchema]);
|
|
63
59
|
|
|
64
60
|
// Prover keystore schema
|
|
65
61
|
const proverKeyStoreSchema = z.union([
|
|
66
62
|
ethAccountSchema,
|
|
67
63
|
z.object({
|
|
68
|
-
id:
|
|
64
|
+
id: schemas.EthAddress,
|
|
69
65
|
publisher: ethAccountsSchema,
|
|
70
66
|
}),
|
|
71
67
|
]);
|
|
@@ -73,26 +69,24 @@ const proverKeyStoreSchema = z.union([
|
|
|
73
69
|
// Validator keystore schema
|
|
74
70
|
const validatorKeyStoreSchema = z.object({
|
|
75
71
|
attester: ethAccountsSchema,
|
|
76
|
-
coinbase:
|
|
77
|
-
publisher: ethAccountsSchema
|
|
78
|
-
feeRecipient:
|
|
79
|
-
remoteSigner: remoteSignerConfigSchema
|
|
80
|
-
fundingAccount: ethAccountSchema
|
|
72
|
+
coinbase: optional(schemas.EthAddress),
|
|
73
|
+
publisher: optional(ethAccountsSchema),
|
|
74
|
+
feeRecipient: AztecAddress.schema,
|
|
75
|
+
remoteSigner: optional(remoteSignerConfigSchema),
|
|
76
|
+
fundingAccount: optional(ethAccountSchema),
|
|
81
77
|
});
|
|
82
78
|
|
|
83
79
|
// Main keystore schema
|
|
84
80
|
export const keystoreSchema = z
|
|
85
81
|
.object({
|
|
86
82
|
schemaVersion: z.literal(1),
|
|
87
|
-
validators: z.array(validatorKeyStoreSchema)
|
|
88
|
-
slasher: ethAccountsSchema
|
|
89
|
-
remoteSigner: remoteSignerConfigSchema
|
|
90
|
-
prover: proverKeyStoreSchema
|
|
91
|
-
fundingAccount: ethAccountSchema
|
|
83
|
+
validators: optional(z.array(validatorKeyStoreSchema)),
|
|
84
|
+
slasher: optional(ethAccountsSchema),
|
|
85
|
+
remoteSigner: optional(remoteSignerConfigSchema),
|
|
86
|
+
prover: optional(proverKeyStoreSchema),
|
|
87
|
+
fundingAccount: optional(ethAccountSchema),
|
|
92
88
|
})
|
|
93
89
|
.refine(data => data.validators || data.prover, {
|
|
94
90
|
message: 'Keystore must have at least validators or prover configuration',
|
|
95
91
|
path: ['root'],
|
|
96
92
|
});
|
|
97
|
-
|
|
98
|
-
export type KeyStoreSchema = z.infer<typeof keystoreSchema>;
|