@aztec/node-keystore 3.0.0-nightly.20251214 → 3.0.0-nightly.20251217

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.
@@ -1 +1 @@
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,aAAa,EAAE,MAAM,YAAY,CAAC;AAG/D,eAAO,MAAM,mBAAmB,kDAGK,CAAC;AACtC,eAAO,MAAM,mBAAmB,kDAGK,CAAC;AA8FtC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAavB,CAAC"}
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,aAAa,EAAE,MAAM,YAAY,CAAC;AAG/D,eAAO,MAAM,mBAAmB,kDAGK,CAAC;AACtC,eAAO,MAAM,mBAAmB,kDAGK,CAAC;AA4JtC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAgD,CAAC"}
package/dest/schemas.js CHANGED
@@ -78,8 +78,8 @@ const proverKeyStoreSchema = z.union([
78
78
  publisher: ethAccountsSchema
79
79
  }).strict()
80
80
  ]);
81
- // Validator keystore schema
82
- const validatorKeyStoreSchema = z.object({
81
+ // Validator keystore schema for v1 (feeRecipient required)
82
+ const validatorKeyStoreSchemaV1 = z.object({
83
83
  attester: attesterAccountsSchema,
84
84
  coinbase: optional(schemas.EthAddress),
85
85
  publisher: optional(ethAccountsSchema),
@@ -87,10 +87,19 @@ const validatorKeyStoreSchema = z.object({
87
87
  remoteSigner: optional(remoteSignerConfigSchema),
88
88
  fundingAccount: optional(ethAccountSchema)
89
89
  }).strict();
90
- // Main keystore schema
91
- export const keystoreSchema = z.object({
90
+ // Validator keystore schema for v2 (feeRecipient optional, can fall back to top-level)
91
+ const validatorKeyStoreSchemaV2 = z.object({
92
+ attester: attesterAccountsSchema,
93
+ coinbase: optional(schemas.EthAddress),
94
+ publisher: optional(ethAccountsSchema),
95
+ feeRecipient: optional(AztecAddress.schema),
96
+ remoteSigner: optional(remoteSignerConfigSchema),
97
+ fundingAccount: optional(ethAccountSchema)
98
+ }).strict();
99
+ // Schema v1 - original format
100
+ const keystoreSchemaV1 = z.object({
92
101
  schemaVersion: z.literal(1),
93
- validators: optional(z.array(validatorKeyStoreSchema)),
102
+ validators: optional(z.array(validatorKeyStoreSchemaV1)),
94
103
  slasher: optional(ethAccountsSchema),
95
104
  remoteSigner: optional(remoteSignerConfigSchema),
96
105
  prover: optional(proverKeyStoreSchema),
@@ -101,3 +110,38 @@ export const keystoreSchema = z.object({
101
110
  'root'
102
111
  ]
103
112
  });
113
+ // Schema v2 - adds top-level publisher, coinbase, feeRecipient
114
+ const keystoreSchemaV2 = z.object({
115
+ schemaVersion: z.literal(2),
116
+ validators: optional(z.array(validatorKeyStoreSchemaV2)),
117
+ slasher: optional(ethAccountsSchema),
118
+ remoteSigner: optional(remoteSignerConfigSchema),
119
+ prover: optional(proverKeyStoreSchema),
120
+ fundingAccount: optional(ethAccountSchema),
121
+ publisher: optional(ethAccountsSchema),
122
+ coinbase: optional(schemas.EthAddress),
123
+ feeRecipient: optional(AztecAddress.schema)
124
+ }).strict().refine((data)=>data.validators || data.prover, {
125
+ message: 'Keystore must have at least validators or prover configuration',
126
+ path: [
127
+ 'root'
128
+ ]
129
+ }).refine((data)=>{
130
+ // If validators are present, ensure each validator has a feeRecipient or there's a top-level feeRecipient
131
+ if (data.validators) {
132
+ const hasTopLevelFeeRecipient = !!data.feeRecipient;
133
+ const allValidatorsHaveFeeRecipient = data.validators.every((v)=>v.feeRecipient);
134
+ return hasTopLevelFeeRecipient || allValidatorsHaveFeeRecipient;
135
+ }
136
+ return true;
137
+ }, {
138
+ message: 'Each validator must have a feeRecipient, or a top-level feeRecipient must be set for all validators',
139
+ path: [
140
+ 'feeRecipient'
141
+ ]
142
+ });
143
+ // Main keystore schema - accepts both v1 and v2
144
+ export const keystoreSchema = z.union([
145
+ keystoreSchemaV1,
146
+ keystoreSchemaV2
147
+ ]);
package/dest/types.d.ts CHANGED
@@ -78,18 +78,19 @@ export type ValidatorKeyStore = {
78
78
  attester: AttesterAccounts;
79
79
  /**
80
80
  * Coinbase address to use when proposing an L2 block as any of the validators in this configuration block.
81
- * Falls back to the attester address if not set.
81
+ * Falls back to the keystore-level coinbase, then to the attester address if not set.
82
82
  */
83
83
  coinbase?: EthAddress;
84
84
  /**
85
85
  * One or more EOAs used for sending block proposal L1 txs for all validators in this configuration block.
86
- * Falls back to the attester account if not set.
86
+ * Falls back to the keystore-level publisher, then to the attester account if not set.
87
87
  */
88
88
  publisher?: EthAccounts;
89
89
  /**
90
90
  * Fee recipient address to use when proposing an L2 block as any of the validators in this configuration block.
91
+ * Falls back to the keystore-level feeRecipient if not set.
91
92
  */
92
- feeRecipient: AztecAddress;
93
+ feeRecipient?: AztecAddress;
93
94
  /**
94
95
  * Default remote signer for all accounts in this block.
95
96
  */
@@ -100,8 +101,8 @@ export type ValidatorKeyStore = {
100
101
  fundingAccount?: EthAccount;
101
102
  };
102
103
  export type KeyStore = {
103
- /** Schema version of this keystore file (initially 1). */
104
- schemaVersion: number;
104
+ /** Schema version of this keystore file (1 or 2). */
105
+ schemaVersion: 1 | 2;
105
106
  /** Validator configurations. */
106
107
  validators?: ValidatorKeyStore[];
107
108
  /** One or more accounts used for creating slash payloads on L1. Does not create slash payloads if not set. */
@@ -112,5 +113,11 @@ export type KeyStore = {
112
113
  prover?: ProverKeyStore;
113
114
  /** Used for automatically funding publisher accounts if there is none defined in the corresponding ValidatorKeyStore*/
114
115
  fundingAccount?: EthAccount;
116
+ /** Default publisher accounts for all validators in this keystore. Can be overridden by individual validator configs. */
117
+ publisher?: EthAccounts;
118
+ /** Default coinbase address for all validators in this keystore. Can be overridden by individual validator configs. */
119
+ coinbase?: EthAddress;
120
+ /** Default fee recipient address for all validators in this keystore. Can be overridden by individual validator configs. */
121
+ feeRecipient?: AztecAddress;
115
122
  };
116
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFDSCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVoRTs7Ozs7R0FLRztBQUNILE1BQU0sTUFBTSxzQkFBc0IsR0FBRztJQUFFLElBQUksRUFBRSxNQUFNLENBQUM7SUFBQyxRQUFRLENBQUMsRUFBRSxNQUFNLENBQUE7Q0FBRSxDQUFDO0FBRXpFLGlEQUFpRDtBQUNqRCxNQUFNLE1BQU0sYUFBYSxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUVwQyxxREFBcUQ7QUFDckQsTUFBTSxNQUFNLGFBQWEsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7QUFFcEMsa0NBQWtDO0FBQ2xDLE1BQU0sTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDO0FBRXpCOztHQUVHO0FBQ0gsTUFBTSxNQUFNLHFCQUFxQixHQUM3QixHQUFHLEdBQ0g7SUFDRSxlQUFlLEVBQUUsR0FBRyxDQUFDO0lBQ3JCLFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNsQixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7Q0FDbkIsQ0FBQztBQUVOOzs7R0FHRztBQUNILE1BQU0sTUFBTSxzQkFBc0IsR0FDOUIsVUFBVSxHQUNWO0lBQ0UsT0FBTyxFQUFFLFVBQVUsQ0FBQztJQUNwQixlQUFlLEVBQUUsR0FBRyxDQUFDO0lBQ3JCLFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNsQixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7Q0FDbkIsQ0FBQztBQUVOLG9IQUFvSDtBQUNwSCxNQUFNLE1BQU0sVUFBVSxHQUFHLGFBQWEsR0FBRyxzQkFBc0IsR0FBRyxzQkFBc0IsQ0FBQztBQUV6Rix5REFBeUQ7QUFDekQsTUFBTSxNQUFNLGNBQWMsR0FBRztJQUMzQixRQUFRLEVBQUUsTUFBTSxDQUFDO0lBQ2pCLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUN0QixZQUFZLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDdEIsWUFBWSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQztDQUN2QixDQUFDO0FBRUYsOEJBQThCO0FBQzlCLE1BQU0sTUFBTSxXQUFXLEdBQUcsVUFBVSxHQUFHLFVBQVUsRUFBRSxHQUFHLGNBQWMsQ0FBQztBQUVyRSxNQUFNLE1BQU0sb0JBQW9CLEdBQUc7SUFDakMsaUZBQWlGO0lBQ2pGLEVBQUUsRUFBRSxVQUFVLENBQUM7SUFDZixzREFBc0Q7SUFDdEQsU0FBUyxFQUFFLFdBQVcsQ0FBQztDQUN4QixDQUFDO0FBRUYsTUFBTSxNQUFNLGNBQWMsR0FBRyxvQkFBb0IsR0FBRyxVQUFVLENBQUM7QUFFL0Qsb0ZBQW9GO0FBQ3BGLE1BQU0sTUFBTSxVQUFVLEdBQUcsYUFBYSxHQUFHLHNCQUFzQixDQUFDO0FBRWhFLDBFQUEwRTtBQUMxRSxNQUFNLE1BQU0sZUFBZSxHQUFHO0lBQUUsR0FBRyxFQUFFLFVBQVUsQ0FBQztJQUFDLEdBQUcsQ0FBQyxFQUFFLFVBQVUsQ0FBQTtDQUFFLEdBQUcsVUFBVSxDQUFDO0FBRWpGLCtEQUErRDtBQUMvRCxNQUFNLE1BQU0sZ0JBQWdCLEdBQUcsZUFBZSxHQUFHLGVBQWUsRUFBRSxHQUFHLGNBQWMsQ0FBQztBQUVwRixNQUFNLE1BQU0saUJBQWlCLEdBQUc7SUFDOUI7OztPQUdHO0lBQ0gsUUFBUSxFQUFFLGdCQUFnQixDQUFDO0lBQzNCOzs7T0FHRztJQUNILFFBQVEsQ0FBQyxFQUFFLFVBQVUsQ0FBQztJQUN0Qjs7O09BR0c7SUFDSCxTQUFTLENBQUMsRUFBRSxXQUFXLENBQUM7SUFDeEI7O09BRUc7SUFDSCxZQUFZLEVBQUUsWUFBWSxDQUFDO0lBQzNCOztPQUVHO0lBQ0gsWUFBWSxDQUFDLEVBQUUscUJBQXFCLENBQUM7SUFDckM7O09BRUc7SUFDSCxjQUFjLENBQUMsRUFBRSxVQUFVLENBQUM7Q0FDN0IsQ0FBQztBQUVGLE1BQU0sTUFBTSxRQUFRLEdBQUc7SUFDckIsMERBQTBEO0lBQzFELGFBQWEsRUFBRSxNQUFNLENBQUM7SUFDdEIsZ0NBQWdDO0lBQ2hDLFVBQVUsQ0FBQyxFQUFFLGlCQUFpQixFQUFFLENBQUM7SUFDakMsOEdBQThHO0lBQzlHLE9BQU8sQ0FBQyxFQUFFLFdBQVcsQ0FBQztJQUN0QiwwRUFBMEU7SUFDMUUsWUFBWSxDQUFDLEVBQUUscUJBQXFCLENBQUM7SUFDckMsc0VBQXNFO0lBQ3RFLE1BQU0sQ0FBQyxFQUFFLGNBQWMsQ0FBQztJQUN4Qix3SEFBd0g7SUFDeEgsY0FBYyxDQUFDLEVBQUUsVUFBVSxDQUFDO0NBQzdCLENBQUMifQ==
123
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFDSCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVoRTs7Ozs7R0FLRztBQUNILE1BQU0sTUFBTSxzQkFBc0IsR0FBRztJQUFFLElBQUksRUFBRSxNQUFNLENBQUM7SUFBQyxRQUFRLENBQUMsRUFBRSxNQUFNLENBQUE7Q0FBRSxDQUFDO0FBRXpFLGlEQUFpRDtBQUNqRCxNQUFNLE1BQU0sYUFBYSxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUVwQyxxREFBcUQ7QUFDckQsTUFBTSxNQUFNLGFBQWEsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7QUFFcEMsa0NBQWtDO0FBQ2xDLE1BQU0sTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDO0FBRXpCOztHQUVHO0FBQ0gsTUFBTSxNQUFNLHFCQUFxQixHQUM3QixHQUFHLEdBQ0g7SUFDRSxlQUFlLEVBQUUsR0FBRyxDQUFDO0lBQ3JCLFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNsQixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7Q0FDbkIsQ0FBQztBQUVOOzs7R0FHRztBQUNILE1BQU0sTUFBTSxzQkFBc0IsR0FDOUIsVUFBVSxHQUNWO0lBQ0UsT0FBTyxFQUFFLFVBQVUsQ0FBQztJQUNwQixlQUFlLEVBQUUsR0FBRyxDQUFDO0lBQ3JCLFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNsQixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7Q0FDbkIsQ0FBQztBQUVOLG9IQUFvSDtBQUNwSCxNQUFNLE1BQU0sVUFBVSxHQUFHLGFBQWEsR0FBRyxzQkFBc0IsR0FBRyxzQkFBc0IsQ0FBQztBQUV6Rix5REFBeUQ7QUFDekQsTUFBTSxNQUFNLGNBQWMsR0FBRztJQUMzQixRQUFRLEVBQUUsTUFBTSxDQUFDO0lBQ2pCLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUN0QixZQUFZLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDdEIsWUFBWSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQztDQUN2QixDQUFDO0FBRUYsOEJBQThCO0FBQzlCLE1BQU0sTUFBTSxXQUFXLEdBQUcsVUFBVSxHQUFHLFVBQVUsRUFBRSxHQUFHLGNBQWMsQ0FBQztBQUVyRSxNQUFNLE1BQU0sb0JBQW9CLEdBQUc7SUFDakMsaUZBQWlGO0lBQ2pGLEVBQUUsRUFBRSxVQUFVLENBQUM7SUFDZixzREFBc0Q7SUFDdEQsU0FBUyxFQUFFLFdBQVcsQ0FBQztDQUN4QixDQUFDO0FBRUYsTUFBTSxNQUFNLGNBQWMsR0FBRyxvQkFBb0IsR0FBRyxVQUFVLENBQUM7QUFFL0Qsb0ZBQW9GO0FBQ3BGLE1BQU0sTUFBTSxVQUFVLEdBQUcsYUFBYSxHQUFHLHNCQUFzQixDQUFDO0FBRWhFLDBFQUEwRTtBQUMxRSxNQUFNLE1BQU0sZUFBZSxHQUFHO0lBQUUsR0FBRyxFQUFFLFVBQVUsQ0FBQztJQUFDLEdBQUcsQ0FBQyxFQUFFLFVBQVUsQ0FBQTtDQUFFLEdBQUcsVUFBVSxDQUFDO0FBRWpGLCtEQUErRDtBQUMvRCxNQUFNLE1BQU0sZ0JBQWdCLEdBQUcsZUFBZSxHQUFHLGVBQWUsRUFBRSxHQUFHLGNBQWMsQ0FBQztBQUVwRixNQUFNLE1BQU0saUJBQWlCLEdBQUc7SUFDOUI7OztPQUdHO0lBQ0gsUUFBUSxFQUFFLGdCQUFnQixDQUFDO0lBQzNCOzs7T0FHRztJQUNILFFBQVEsQ0FBQyxFQUFFLFVBQVUsQ0FBQztJQUN0Qjs7O09BR0c7SUFDSCxTQUFTLENBQUMsRUFBRSxXQUFXLENBQUM7SUFDeEI7OztPQUdHO0lBQ0gsWUFBWSxDQUFDLEVBQUUsWUFBWSxDQUFDO0lBQzVCOztPQUVHO0lBQ0gsWUFBWSxDQUFDLEVBQUUscUJBQXFCLENBQUM7SUFDckM7O09BRUc7SUFDSCxjQUFjLENBQUMsRUFBRSxVQUFVLENBQUM7Q0FDN0IsQ0FBQztBQUVGLE1BQU0sTUFBTSxRQUFRLEdBQUc7SUFDckIscURBQXFEO0lBQ3JELGFBQWEsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3JCLGdDQUFnQztJQUNoQyxVQUFVLENBQUMsRUFBRSxpQkFBaUIsRUFBRSxDQUFDO0lBQ2pDLDhHQUE4RztJQUM5RyxPQUFPLENBQUMsRUFBRSxXQUFXLENBQUM7SUFDdEIsMEVBQTBFO0lBQzFFLFlBQVksQ0FBQyxFQUFFLHFCQUFxQixDQUFDO0lBQ3JDLHNFQUFzRTtJQUN0RSxNQUFNLENBQUMsRUFBRSxjQUFjLENBQUM7SUFDeEIsd0hBQXdIO0lBQ3hILGNBQWMsQ0FBQyxFQUFFLFVBQVUsQ0FBQztJQUM1Qix5SEFBeUg7SUFDekgsU0FBUyxDQUFDLEVBQUUsV0FBVyxDQUFDO0lBQ3hCLHVIQUF1SDtJQUN2SCxRQUFRLENBQUMsRUFBRSxVQUFVLENBQUM7SUFDdEIsNEhBQTRIO0lBQzVILFlBQVksQ0FBQyxFQUFFLFlBQVksQ0FBQztDQUM3QixDQUFDIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/node-keystore",
3
- "version": "3.0.0-nightly.20251214",
3
+ "version": "3.0.0-nightly.20251217",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -64,9 +64,9 @@
64
64
  ]
65
65
  },
66
66
  "dependencies": {
67
- "@aztec/ethereum": "3.0.0-nightly.20251214",
68
- "@aztec/foundation": "3.0.0-nightly.20251214",
69
- "@aztec/stdlib": "3.0.0-nightly.20251214",
67
+ "@aztec/ethereum": "3.0.0-nightly.20251217",
68
+ "@aztec/foundation": "3.0.0-nightly.20251217",
69
+ "@aztec/stdlib": "3.0.0-nightly.20251217",
70
70
  "@ethersproject/wallet": "^5.7.0",
71
71
  "tslib": "^2.4.0",
72
72
  "viem": "npm:@aztec/viem@2.38.2",
@@ -228,7 +228,7 @@ export class KeystoreManager {
228
228
  }
229
229
 
230
230
  /**
231
- * 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)
232
232
  */
233
233
  createPublisherSigners(validatorIndex: number): EthSigner[] {
234
234
  const validator = this.getValidator(validatorIndex);
@@ -240,6 +240,14 @@ export class KeystoreManager {
240
240
  );
241
241
  }
242
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
+
243
251
  // Fall back to attester signers
244
252
  return this.createAttesterSigners(validatorIndex);
245
253
  }
@@ -320,7 +328,7 @@ export class KeystoreManager {
320
328
  }
321
329
 
322
330
  /**
323
- * Get coinbase address for validator (falls back to the specific attester address)
331
+ * Get coinbase address for validator (falls back to keystore-level coinbase, then to the specific attester address)
324
332
  */
325
333
  getCoinbaseAddress(validatorIndex: number, attesterAddress: EthAddress): EthAddress {
326
334
  const validator = this.getValidator(validatorIndex);
@@ -329,16 +337,33 @@ export class KeystoreManager {
329
337
  return validator.coinbase;
330
338
  }
331
339
 
340
+ // Fall back to keystore-level coinbase
341
+ if (this.keystore.coinbase) {
342
+ return this.keystore.coinbase;
343
+ }
344
+
332
345
  // Fall back to the specific attester address
333
346
  return attesterAddress;
334
347
  }
335
348
 
336
349
  /**
337
- * Get fee recipient for validator
350
+ * Get fee recipient for validator (falls back to keystore-level feeRecipient)
338
351
  */
339
352
  getFeeRecipient(validatorIndex: number): AztecAddress {
340
353
  const validator = this.getValidator(validatorIndex);
341
- 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
+ );
342
367
  }
343
368
 
344
369
  /**
package/src/loader.ts CHANGED
@@ -208,12 +208,18 @@ export function mergeKeystores(keystores: KeyStore[]): KeyStore {
208
208
  // Track attester addresses to prevent duplicates
209
209
  const attesterAddresses = new Set<string>();
210
210
 
211
+ // Determine schema version: use v2 if any input is v2
212
+ const schemaVersion = keystores.some(ks => ks.schemaVersion === 2) ? 2 : 1;
213
+
211
214
  const merged: KeyStore = {
212
- schemaVersion: 1,
215
+ schemaVersion,
213
216
  validators: [],
214
217
  slasher: undefined,
215
218
  remoteSigner: undefined,
216
219
  prover: undefined,
220
+ publisher: undefined,
221
+ coinbase: undefined,
222
+ feeRecipient: undefined,
217
223
  };
218
224
 
219
225
  for (let i = 0; i < keystores.length; i++) {
@@ -234,8 +240,18 @@ export function mergeKeystores(keystores: KeyStore[]): KeyStore {
234
240
  }
235
241
  attesterAddresses.add(key);
236
242
  }
243
+
244
+ // When merging v1 validators into a v2+ result, preserve original fallback behavior
245
+ // by explicitly setting publisher/coinbase/feeRecipient if they're missing
246
+ if (keystore.schemaVersion !== schemaVersion) {
247
+ throw new KeyStoreLoadError(
248
+ `Cannot merge keystores with different schema versions: ${keystore.schemaVersion} and ${schemaVersion}`,
249
+ `keystores[${i}].schemaVersion`,
250
+ );
251
+ } else {
252
+ merged.validators!.push(validator);
253
+ }
237
254
  }
238
- merged.validators!.push(...keystore.validators);
239
255
  }
240
256
 
241
257
  // Merge slasher (accumulate all)
@@ -268,6 +284,45 @@ export function mergeKeystores(keystores: KeyStore[]): KeyStore {
268
284
  }
269
285
  merged.prover = keystore.prover;
270
286
  }
287
+
288
+ // Merge top-level publisher (accumulate all, unless conflicting MnemonicConfigs)
289
+ if (keystore.publisher) {
290
+ if (!merged.publisher) {
291
+ merged.publisher = keystore.publisher;
292
+ } else {
293
+ const isMnemonic = (accounts: EthAccounts): boolean =>
294
+ typeof accounts === 'object' && accounts !== null && 'mnemonic' in accounts;
295
+
296
+ // If either is a mnemonic, warn and use last one (can't merge mnemonics)
297
+ if (isMnemonic(merged.publisher) || isMnemonic(keystore.publisher)) {
298
+ logger.warn(
299
+ 'Multiple default publisher configurations found with mnemonic, using the last one (cannot merge mnemonics)',
300
+ );
301
+ merged.publisher = keystore.publisher;
302
+ } else {
303
+ // Both are non-mnemonic, accumulate them
304
+ const toArray = (accounts: EthAccounts): unknown[] => (Array.isArray(accounts) ? accounts : [accounts]);
305
+ const combined = [...toArray(merged.publisher), ...toArray(keystore.publisher)];
306
+ merged.publisher = combined as unknown as EthAccounts;
307
+ }
308
+ }
309
+ }
310
+
311
+ // Merge top-level coinbase (last one wins, but warn about conflicts)
312
+ if (keystore.coinbase) {
313
+ if (merged.coinbase) {
314
+ logger.warn('Multiple default coinbase addresses found, using the last one');
315
+ }
316
+ merged.coinbase = keystore.coinbase;
317
+ }
318
+
319
+ // Merge top-level feeRecipient (last one wins, but warn about conflicts)
320
+ if (keystore.feeRecipient) {
321
+ if (merged.feeRecipient) {
322
+ logger.warn('Multiple default feeRecipient addresses found, using the last one');
323
+ }
324
+ merged.feeRecipient = keystore.feeRecipient;
325
+ }
271
326
  }
272
327
 
273
328
  // Clean up empty arrays
package/src/schemas.ts CHANGED
@@ -97,8 +97,8 @@ const proverKeyStoreSchema = z.union([
97
97
  .strict(),
98
98
  ]);
99
99
 
100
- // Validator keystore schema
101
- const validatorKeyStoreSchema = z
100
+ // Validator keystore schema for v1 (feeRecipient required)
101
+ const validatorKeyStoreSchemaV1 = z
102
102
  .object({
103
103
  attester: attesterAccountsSchema,
104
104
  coinbase: optional(schemas.EthAddress),
@@ -109,11 +109,23 @@ const validatorKeyStoreSchema = z
109
109
  })
110
110
  .strict();
111
111
 
112
- // Main keystore schema
113
- export const keystoreSchema = z
112
+ // Validator keystore schema for v2 (feeRecipient optional, can fall back to top-level)
113
+ const validatorKeyStoreSchemaV2 = z
114
+ .object({
115
+ attester: attesterAccountsSchema,
116
+ coinbase: optional(schemas.EthAddress),
117
+ publisher: optional(ethAccountsSchema),
118
+ feeRecipient: optional(AztecAddress.schema),
119
+ remoteSigner: optional(remoteSignerConfigSchema),
120
+ fundingAccount: optional(ethAccountSchema),
121
+ })
122
+ .strict();
123
+
124
+ // Schema v1 - original format
125
+ const keystoreSchemaV1 = z
114
126
  .object({
115
127
  schemaVersion: z.literal(1),
116
- validators: optional(z.array(validatorKeyStoreSchema)),
128
+ validators: optional(z.array(validatorKeyStoreSchemaV1)),
117
129
  slasher: optional(ethAccountsSchema),
118
130
  remoteSigner: optional(remoteSignerConfigSchema),
119
131
  prover: optional(proverKeyStoreSchema),
@@ -124,3 +136,40 @@ export const keystoreSchema = z
124
136
  message: 'Keystore must have at least validators or prover configuration',
125
137
  path: ['root'],
126
138
  });
139
+
140
+ // Schema v2 - adds top-level publisher, coinbase, feeRecipient
141
+ const keystoreSchemaV2 = z
142
+ .object({
143
+ schemaVersion: z.literal(2),
144
+ validators: optional(z.array(validatorKeyStoreSchemaV2)),
145
+ slasher: optional(ethAccountsSchema),
146
+ remoteSigner: optional(remoteSignerConfigSchema),
147
+ prover: optional(proverKeyStoreSchema),
148
+ fundingAccount: optional(ethAccountSchema),
149
+ publisher: optional(ethAccountsSchema),
150
+ coinbase: optional(schemas.EthAddress),
151
+ feeRecipient: optional(AztecAddress.schema),
152
+ })
153
+ .strict()
154
+ .refine(data => data.validators || data.prover, {
155
+ message: 'Keystore must have at least validators or prover configuration',
156
+ path: ['root'],
157
+ })
158
+ .refine(
159
+ data => {
160
+ // If validators are present, ensure each validator has a feeRecipient or there's a top-level feeRecipient
161
+ if (data.validators) {
162
+ const hasTopLevelFeeRecipient = !!data.feeRecipient;
163
+ const allValidatorsHaveFeeRecipient = data.validators.every(v => v.feeRecipient);
164
+ return hasTopLevelFeeRecipient || allValidatorsHaveFeeRecipient;
165
+ }
166
+ return true;
167
+ },
168
+ {
169
+ message: 'Each validator must have a feeRecipient, or a top-level feeRecipient must be set for all validators',
170
+ path: ['feeRecipient'],
171
+ },
172
+ );
173
+
174
+ // Main keystore schema - accepts both v1 and v2
175
+ export const keystoreSchema = z.union([keystoreSchemaV1, keystoreSchemaV2]);
package/src/types.ts CHANGED
@@ -91,18 +91,19 @@ export type ValidatorKeyStore = {
91
91
  attester: AttesterAccounts;
92
92
  /**
93
93
  * Coinbase address to use when proposing an L2 block as any of the validators in this configuration block.
94
- * Falls back to the attester address if not set.
94
+ * Falls back to the keystore-level coinbase, then to the attester address if not set.
95
95
  */
96
96
  coinbase?: EthAddress;
97
97
  /**
98
98
  * One or more EOAs used for sending block proposal L1 txs for all validators in this configuration block.
99
- * Falls back to the attester account if not set.
99
+ * Falls back to the keystore-level publisher, then to the attester account if not set.
100
100
  */
101
101
  publisher?: EthAccounts;
102
102
  /**
103
103
  * Fee recipient address to use when proposing an L2 block as any of the validators in this configuration block.
104
+ * Falls back to the keystore-level feeRecipient if not set.
104
105
  */
105
- feeRecipient: AztecAddress;
106
+ feeRecipient?: AztecAddress;
106
107
  /**
107
108
  * Default remote signer for all accounts in this block.
108
109
  */
@@ -114,8 +115,8 @@ export type ValidatorKeyStore = {
114
115
  };
115
116
 
116
117
  export type KeyStore = {
117
- /** Schema version of this keystore file (initially 1). */
118
- schemaVersion: number;
118
+ /** Schema version of this keystore file (1 or 2). */
119
+ schemaVersion: 1 | 2;
119
120
  /** Validator configurations. */
120
121
  validators?: ValidatorKeyStore[];
121
122
  /** One or more accounts used for creating slash payloads on L1. Does not create slash payloads if not set. */
@@ -126,4 +127,10 @@ export type KeyStore = {
126
127
  prover?: ProverKeyStore;
127
128
  /** Used for automatically funding publisher accounts if there is none defined in the corresponding ValidatorKeyStore*/
128
129
  fundingAccount?: EthAccount;
130
+ /** Default publisher accounts for all validators in this keystore. Can be overridden by individual validator configs. */
131
+ publisher?: EthAccounts;
132
+ /** Default coinbase address for all validators in this keystore. Can be overridden by individual validator configs. */
133
+ coinbase?: EthAddress;
134
+ /** Default fee recipient address for all validators in this keystore. Can be overridden by individual validator configs. */
135
+ feeRecipient?: AztecAddress;
129
136
  };