@provablehq/sdk 0.10.2-rc.1 → 0.10.2

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,360 +1,9 @@
1
1
  import 'core-js/proposals/json-parse-with-source.js';
2
- import { ProvingKey, VerifyingKey, ViewKey, ComputeKey, Address, PrivateKeyCiphertext, PrivateKey, RecordCiphertext, EncryptionToolkit, Group, Metadata, Program, Plaintext, Transaction, ProvingRequest, RecordPlaintext, Field, Poseidon4, ProgramImports, ProgramManager as ProgramManager$1, ExecutionRequest, stringToField, verifyFunctionExecution, Value, Proof, Signature } from '@provablehq/wasm/testnet.js';
3
- export { Address, Authorization, BHP1024, BHP256, BHP512, BHP768, Boolean, Ciphertext, ComputeKey, DynamicRecord, EncryptionToolkit, ExecutionRequest, ExecutionResponse, Field, Execution as FunctionExecution, GraphKey, Group, I128, I16, I32, I64, I8, OfflineQuery, Pedersen128, Pedersen64, Plaintext, Poseidon2, Poseidon4, Poseidon8, PrivateKey, PrivateKeyCiphertext, Program, ProgramImports as ProgramImportsBuilder, ProgramManager as ProgramManagerBase, Proof, ProvingKey, ProvingRequest, RecordCiphertext, RecordPlaintext, Scalar, Signature, Transaction, Transition, U128, U16, U32, U64, U8, Value, VerifyingKey, ViewKey, getOrInitConsensusVersionTestHeights, initThreadPool, snarkVerify, snarkVerifyBatch, stringToField, verifyFunctionExecution } from '@provablehq/wasm/testnet.js';
2
+ import { ViewKey, ComputeKey, Address, PrivateKeyCiphertext, PrivateKey, RecordCiphertext, EncryptionToolkit, Group, Metadata, VerifyingKey, Program, Plaintext, Transaction, ProvingRequest, ProvingKey, RecordPlaintext, Field, Poseidon4, ProgramManager as ProgramManager$1, ExecutionRequest, stringToField, verifyFunctionExecution, Value, Proof, Signature } from '@provablehq/wasm/testnet.js';
3
+ export { Address, Authorization, BHP1024, BHP256, BHP512, BHP768, Boolean, Ciphertext, ComputeKey, DynamicRecord, EncryptionToolkit, ExecutionRequest, ExecutionResponse, Field, Execution as FunctionExecution, GraphKey, Group, I128, I16, I32, I64, I8, OfflineQuery, Pedersen128, Pedersen64, Plaintext, Poseidon2, Poseidon4, Poseidon8, PrivateKey, PrivateKeyCiphertext, Program, ProgramManager as ProgramManagerBase, Proof, ProvingKey, ProvingRequest, RecordCiphertext, RecordPlaintext, Scalar, Signature, Transaction, Transition, U128, U16, U32, U64, U8, Value, VerifyingKey, ViewKey, getOrInitConsensusVersionTestHeights, initThreadPool, snarkVerify, snarkVerifyBatch, stringToField, verifyFunctionExecution } from '@provablehq/wasm/testnet.js';
4
4
  import sodium from 'libsodium-wrappers';
5
5
  import { bech32m } from '@scure/base';
6
6
 
7
- /**
8
- * Error thrown when a key locator is invalid for filesystem use.
9
- * Used to prevent path traversal and other filesystem injection when deriving paths from locators.
10
- *
11
- * @extends Error
12
- */
13
- class InvalidLocatorError extends Error {
14
- locator;
15
- reason;
16
- /**
17
- * @param message - Human-readable description of the validation failure.
18
- * @param locator - The invalid locator string that failed validation.
19
- * @param reason - Machine-readable reason code for the failure.
20
- */
21
- constructor(message, locator, reason) {
22
- super(message);
23
- this.locator = locator;
24
- this.reason = reason;
25
- this.name = "InvalidLocatorError";
26
- Object.setPrototypeOf(this, InvalidLocatorError.prototype);
27
- }
28
- }
29
-
30
- /**
31
- * Error thrown when there is a mismatch between expected and actual key metadata.
32
- * This can occur during verification of either the checksum or size of a key.
33
- *
34
- * @extends Error
35
- */
36
- class KeyVerificationError extends Error {
37
- locator;
38
- field;
39
- expected;
40
- actual;
41
- /**
42
- * Creates a new KeyVerificationError instance (error.name is "ChecksumMismatchError").
43
- *
44
- * @param {string} locator - The key locator where the mismatch occurred.
45
- * @param {"checksum" | "size"} field - The field that failed verification (either "checksum" or "size").
46
- * @param {string} expected - The expected value of the field.
47
- * @param {string} actual - The actual value encountered.
48
- */
49
- constructor(locator, field, expected, actual) {
50
- super(`Key verification ${locator} ${field} mismatch: expected ${expected}, got ${actual}`);
51
- this.locator = locator;
52
- this.field = field;
53
- this.expected = expected;
54
- this.actual = actual;
55
- this.name = "ChecksumMismatchError";
56
- Object.setPrototypeOf(this, KeyVerificationError.prototype);
57
- }
58
- }
59
- /**
60
- * Computes the SHA-256 checksum of a given set of bytes.
61
- *
62
- * @param {Uint8Array} bytes - The bytes to compute the checksum of.
63
- */
64
- async function sha256Hex(bytes) {
65
- const hash = await crypto.subtle.digest("SHA-256", bytes);
66
- return Array.from(new Uint8Array(hash))
67
- .map((b) => b.toString(16).padStart(2, "0"))
68
- .join("");
69
- }
70
-
71
- /**
72
- * In-memory implementation of KeyVerifier that stores and verifies key fingerprints.
73
- * Provides functionality to compute and verify cryptographic checksums of keys, storing them
74
- * in memory for subsequent verification. This implementation is primarily used for testing
75
- * and development purposes where persistence is not required.
76
- *
77
- * Key features:
78
- * - Computes SHA-256 checksums and sizes for key bytes.
79
- * - Stores key fingerprints in memory using string locators.
80
- * - Verifies key bytes against stored or provided fingerprints.
81
- *
82
- * @implements {KeyVerifier}
83
- */
84
- class MemKeyVerifier {
85
- keyStore = {};
86
- /**
87
- * Computes and optionally stores key metadata. If a keyFingerprint is provided, this function will verify the computed checksum against it before storing it.
88
- *
89
- * @param {KeyMetadata} keyMetadata - Object containing key bytes and optional verification data.
90
- * @throws {KeyVerificationError} When provided keyFingerprint doesn't match computed values.
91
- * @returns {Promise<KeyFingerprint>} Computed key metadata.
92
- */
93
- async computeKeyMetadata(keyMetadata) {
94
- // Compute the metadata from the key bytes
95
- const computedFingerprint = {
96
- checksum: await sha256Hex(keyMetadata.keyBytes),
97
- size: keyMetadata.keyBytes.length
98
- };
99
- // If a KeyFingerprint is provided, verify it matches computed values.
100
- if (keyMetadata.fingerprint) {
101
- if (keyMetadata.fingerprint.size !== computedFingerprint.size) {
102
- throw new KeyVerificationError(keyMetadata.locator ? keyMetadata.locator : "", "size", String(keyMetadata.fingerprint.size), String(computedFingerprint.size));
103
- }
104
- if (keyMetadata.fingerprint.checksum !== computedFingerprint.checksum) {
105
- throw new KeyVerificationError(keyMetadata.locator ? keyMetadata.locator : "", "checksum", keyMetadata.fingerprint.checksum, computedFingerprint.checksum);
106
- }
107
- }
108
- // If locator is provided, store only the fingerprint
109
- if (keyMetadata.locator) {
110
- this.keyStore[keyMetadata.locator] = computedFingerprint;
111
- }
112
- return computedFingerprint;
113
- }
114
- /**
115
- * Verifies key bytes against stored or provided metadata. Follows a priority verification scheme:
116
- * 1. If KeyFingerprint is provided in the metadata, this method verifies against that first.
117
- * 2. If a locator is provided, attempts to verify against stored fingerprint.
118
- * 3. If neither is available, throws an error.
119
- *
120
- * @param {KeyMetadata} keyMetadata - Object containing the key bytes and optional verification metadata.
121
- * @throws {Error} When neither fingerprint nor valid locator is provided for verification.
122
- * @throws {KeyVerificationError} When size or checksum verification fails.
123
- * @returns {Promise<void>} Promise that resolves when verification succeeds.
124
- */
125
- async verifyKeyBytes(keyMetadata) {
126
- if (!keyMetadata.keyBytes) {
127
- throw new Error("Key bytes must be provided for verification.");
128
- }
129
- // Compute the fingerprint for the provided bytes.
130
- const computedFingerprint = await this.computeKeyMetadata({
131
- keyBytes: keyMetadata.keyBytes
132
- });
133
- // Determine which fingerprint to verify against.
134
- let fingerprintToVerify;
135
- if (keyMetadata.fingerprint) {
136
- // If a key fingerprint is provided, use it.
137
- fingerprintToVerify = keyMetadata.fingerprint;
138
- }
139
- else if (keyMetadata.locator) {
140
- // Otherwise try to get stored fingerprint by locator.
141
- fingerprintToVerify = this.keyStore[keyMetadata.locator];
142
- }
143
- if (!fingerprintToVerify) {
144
- throw new Error("Either fingerprint or a valid locator must be provided for verification.");
145
- }
146
- // Verify the key size.
147
- if (fingerprintToVerify.size !== computedFingerprint.size) {
148
- throw new KeyVerificationError(keyMetadata.locator || "", "size", String(fingerprintToVerify.size), String(computedFingerprint.size));
149
- }
150
- // Verify the key checksum.
151
- if (fingerprintToVerify.checksum !== computedFingerprint.checksum) {
152
- throw new KeyVerificationError(keyMetadata.locator || "", "checksum", fingerprintToVerify.checksum, computedFingerprint.checksum);
153
- }
154
- }
155
- }
156
-
157
- /**
158
- * Browser-compatible {@link KeyStore} backed by IndexedDB.
159
- *
160
- * This is the browser counterpart to {@link LocalFileKeyStore} (which requires Node.js `fs`).
161
- * It persists proving and verifying keys across page reloads and browser sessions using the
162
- * IndexedDB API available in all modern browsers and Web Workers.
163
- *
164
- * @example
165
- * ```ts
166
- * import { IndexedDBKeyStore, ProgramManager } from "@provablehq/sdk";
167
- *
168
- * const keyStore = new IndexedDBKeyStore();
169
- * const pm = new ProgramManager();
170
- * pm.setKeyStore(keyStore);
171
- * // Keys synthesized during execution are now cached in IndexedDB
172
- * // and reloaded automatically on subsequent runs.
173
- * ```
174
- */
175
- class IndexedDBKeyStore {
176
- dbName;
177
- storeName = "keys";
178
- keyVerifier = new MemKeyVerifier();
179
- dbPromise = null;
180
- /**
181
- * @param dbName IndexedDB database name. Defaults to `"aleo-keystore"`.
182
- */
183
- constructor(dbName = "aleo-keystore") {
184
- this.dbName = dbName;
185
- }
186
- // -------------------------------------------------------
187
- // IndexedDB helpers
188
- // -------------------------------------------------------
189
- /** Opens (or creates) the database, returning a cached promise. */
190
- openDB() {
191
- if (this.dbPromise)
192
- return this.dbPromise;
193
- this.dbPromise = new Promise((resolve, reject) => {
194
- const request = indexedDB.open(this.dbName, 1);
195
- request.onupgradeneeded = () => {
196
- const db = request.result;
197
- if (!db.objectStoreNames.contains(this.storeName)) {
198
- db.createObjectStore(this.storeName, { keyPath: "locator" });
199
- }
200
- };
201
- request.onsuccess = () => resolve(request.result);
202
- request.onerror = () => {
203
- this.dbPromise = null;
204
- reject(request.error);
205
- };
206
- request.onblocked = () => {
207
- this.dbPromise = null;
208
- reject(new DOMException("Database open blocked", "AbortError"));
209
- };
210
- });
211
- return this.dbPromise;
212
- }
213
- /** Runs a single read-write transaction and returns the request result. */
214
- async tx(mode, fn) {
215
- const db = await this.openDB();
216
- return new Promise((resolve, reject) => {
217
- const txn = db.transaction(this.storeName, mode);
218
- const store = txn.objectStore(this.storeName);
219
- const req = fn(store);
220
- let result;
221
- req.onsuccess = () => { result = req.result; };
222
- txn.oncomplete = () => resolve(result);
223
- txn.onerror = () => reject(txn.error);
224
- txn.onabort = () => reject(txn.error ?? new DOMException("Transaction aborted", "AbortError"));
225
- });
226
- }
227
- // -------------------------------------------------------
228
- // Locator serialization (mirrors LocalFileKeyStore)
229
- // -------------------------------------------------------
230
- validateComponent(value, label) {
231
- if (value === "" || value === ".") {
232
- throw new InvalidLocatorError(`KeyLocator ${label} must not be empty or "." (got "${value}")`, value, "reserved_name");
233
- }
234
- if (value.includes("..")) {
235
- throw new InvalidLocatorError(`KeyLocator ${label} must not contain ".." (got "${value}")`, value, "path_traversal");
236
- }
237
- if (value.includes("/") || value.includes("\\") || value.includes("\0")) {
238
- throw new InvalidLocatorError(`KeyLocator ${label} must not contain path separators or null bytes (got "${value}")`, value, "path_separator");
239
- }
240
- }
241
- validateNonNegative(value, label) {
242
- if (!Number.isInteger(value) || value < 0) {
243
- throw new InvalidLocatorError(`KeyLocator ${label} must be a non-negative integer (got ${value})`, String(value), "negative_value");
244
- }
245
- }
246
- serializeLocator(locator) {
247
- this.validateComponent(locator.program, "program");
248
- this.validateComponent(locator.functionName, "functionName");
249
- this.validateComponent(locator.network, "network");
250
- this.validateNonNegative(locator.edition, "edition");
251
- this.validateNonNegative(locator.amendment, "amendment");
252
- const base = `${locator.program}.${locator.functionName}.e${locator.edition}.a${locator.amendment}.${locator.network}.${locator.keyType}`;
253
- if (locator.keyType === "translation") {
254
- this.validateComponent(locator.recordName, "recordName");
255
- this.validateNonNegative(locator.recordInputPosition, "recordInputPosition");
256
- return `${base}.${locator.recordName}.${locator.recordInputPosition}`;
257
- }
258
- return base;
259
- }
260
- checksumToFingerprint(checksum, keyBytes) {
261
- if (!checksum)
262
- return undefined;
263
- return { checksum, size: keyBytes.length };
264
- }
265
- // -------------------------------------------------------
266
- // KeyStore interface
267
- // -------------------------------------------------------
268
- async getKeyBytes(locator) {
269
- const key = this.serializeLocator(locator);
270
- const record = await this.tx("readonly", (store) => store.get(key));
271
- if (!record)
272
- return null;
273
- const fingerprint = this.checksumToFingerprint(locator.checksum, record.bytes) ?? record.metadata;
274
- if (fingerprint) {
275
- await this.keyVerifier.verifyKeyBytes({
276
- keyBytes: record.bytes,
277
- locator: key,
278
- fingerprint,
279
- });
280
- }
281
- return record.bytes;
282
- }
283
- async getProvingKey(locator) {
284
- const bytes = await this.getKeyBytes(locator);
285
- if (!bytes)
286
- return null;
287
- return ProvingKey.fromBytes(bytes);
288
- }
289
- async getVerifyingKey(locator) {
290
- const bytes = await this.getKeyBytes(locator);
291
- if (!bytes)
292
- return null;
293
- return VerifyingKey.fromBytes(bytes);
294
- }
295
- async setKeys(proverLocator, verifierLocator, keys) {
296
- const proverKey = this.serializeLocator(proverLocator);
297
- const verifierKey = this.serializeLocator(verifierLocator);
298
- const [provingKey, verifyingKey] = keys;
299
- const [provingKeyBytes, verifyingKeyBytes] = [
300
- provingKey.toBytes(),
301
- verifyingKey.toBytes(),
302
- ];
303
- const [proverFingerprint, verifierFingerprint] = await Promise.all([
304
- this.keyVerifier.computeKeyMetadata({
305
- keyBytes: provingKeyBytes,
306
- locator: proverKey,
307
- fingerprint: this.checksumToFingerprint(proverLocator.checksum, provingKeyBytes),
308
- }),
309
- this.keyVerifier.computeKeyMetadata({
310
- keyBytes: verifyingKeyBytes,
311
- locator: verifierKey,
312
- fingerprint: this.checksumToFingerprint(verifierLocator.checksum, verifyingKeyBytes),
313
- }),
314
- ]);
315
- const proverRecord = { locator: proverKey, bytes: provingKeyBytes, metadata: proverFingerprint };
316
- const verifierRecord = { locator: verifierKey, bytes: verifyingKeyBytes, metadata: verifierFingerprint };
317
- // Write both in a single transaction for atomicity.
318
- const db = await this.openDB();
319
- await new Promise((resolve, reject) => {
320
- const txn = db.transaction(this.storeName, "readwrite");
321
- const store = txn.objectStore(this.storeName);
322
- store.put(proverRecord);
323
- store.put(verifierRecord);
324
- txn.oncomplete = () => resolve();
325
- txn.onerror = () => reject(txn.error);
326
- txn.onabort = () => reject(txn.error ?? new DOMException("Transaction aborted", "AbortError"));
327
- });
328
- }
329
- async setKeyBytes(keyBytes, locator) {
330
- const key = this.serializeLocator(locator);
331
- const computedMetadata = await this.keyVerifier.computeKeyMetadata({
332
- keyBytes,
333
- locator: key,
334
- fingerprint: this.checksumToFingerprint(locator.checksum, keyBytes),
335
- });
336
- const record = { locator: key, bytes: keyBytes, metadata: computedMetadata };
337
- await this.tx("readwrite", (store) => store.put(record));
338
- }
339
- async getKeyMetadata(locator) {
340
- const key = this.serializeLocator(locator);
341
- const record = await this.tx("readonly", (store) => store.get(key));
342
- return record?.metadata ?? null;
343
- }
344
- async has(locator) {
345
- const key = this.serializeLocator(locator);
346
- const count = await this.tx("readonly", (store) => store.count(IDBKeyRange.only(key)));
347
- return count > 0;
348
- }
349
- async delete(locator) {
350
- const key = this.serializeLocator(locator);
351
- await this.tx("readwrite", (store) => store.delete(key));
352
- }
353
- async clear() {
354
- await this.tx("readwrite", (store) => store.clear());
355
- }
356
- }
357
-
358
7
  await sodium.ready;
359
8
  /**
360
9
  * Encrypt an authorization with a libsodium cryptobox public key.
@@ -1200,7 +849,7 @@ class AleoNetworkClient {
1200
849
  else {
1201
850
  this.headers = {
1202
851
  // This is replaced by the actual version by a Rollup plugin
1203
- "X-Aleo-SDK-Version": "0.10.2-rc.1",
852
+ "X-Aleo-SDK-Version": "0.10.2",
1204
853
  "X-Aleo-environment": environment(),
1205
854
  };
1206
855
  }
@@ -1216,7 +865,7 @@ class AleoNetworkClient {
1216
865
  else {
1217
866
  this.headers = {
1218
867
  // This is replaced by the actual version by a Rollup plugin
1219
- "X-Aleo-SDK-Version": "0.10.2-rc.1",
868
+ "X-Aleo-SDK-Version": "0.10.2",
1220
869
  "X-Aleo-environment": environment(),
1221
870
  };
1222
871
  }
@@ -2030,30 +1679,6 @@ class AleoNetworkClient {
2030
1679
  this.ctx = {};
2031
1680
  }
2032
1681
  }
2033
- /**
2034
- * Returns the current edition and amendment count for a program.
2035
- *
2036
- * @param {string} programId - The program ID (e.g. "hello_hello.aleo")
2037
- * @returns {{ program_id: string, edition: number, amendment_count: number }}
2038
- *
2039
- * @example
2040
- * const networkClient = new AleoNetworkClient("https://api.provable.com/v2");
2041
- * const info = await networkClient.getProgramAmendmentCount("hello_hello.aleo");
2042
- * console.log(info.edition, info.amendment_count);
2043
- */
2044
- async getProgramAmendmentCount(programId) {
2045
- try {
2046
- this.ctx = { "X-ALEO-METHOD": "getProgramAmendmentCount" };
2047
- const raw = await this.fetchRaw("/programs/" + programId + "/amendment_count");
2048
- return JSON.parse(raw);
2049
- }
2050
- catch (error) {
2051
- throw new Error(`Error fetching amendment count for ${programId}: ${error}`);
2052
- }
2053
- finally {
2054
- this.ctx = {};
2055
- }
2056
- }
2057
1682
  /**
2058
1683
  * Returns a program object from a program ID or program source code.
2059
1684
  *
@@ -3375,8 +3000,158 @@ class AleoKeyProvider {
3375
3000
  }
3376
3001
  }
3377
3002
  }
3378
- unBondPublicKeys() {
3379
- return this.fetchCreditsKeys(CREDITS_PROGRAM_KEYS.unbond_public);
3003
+ unBondPublicKeys() {
3004
+ return this.fetchCreditsKeys(CREDITS_PROGRAM_KEYS.unbond_public);
3005
+ }
3006
+ }
3007
+
3008
+ /**
3009
+ * Error thrown when there is a mismatch between expected and actual key metadata.
3010
+ * This can occur during verification of either the checksum or size of a key.
3011
+ *
3012
+ * @extends Error
3013
+ */
3014
+ class KeyVerificationError extends Error {
3015
+ locator;
3016
+ field;
3017
+ expected;
3018
+ actual;
3019
+ /**
3020
+ * Creates a new KeyVerificationError instance (error.name is "ChecksumMismatchError").
3021
+ *
3022
+ * @param {string} locator - The key locator where the mismatch occurred.
3023
+ * @param {"checksum" | "size"} field - The field that failed verification (either "checksum" or "size").
3024
+ * @param {string} expected - The expected value of the field.
3025
+ * @param {string} actual - The actual value encountered.
3026
+ */
3027
+ constructor(locator, field, expected, actual) {
3028
+ super(`Key verification ${locator} ${field} mismatch: expected ${expected}, got ${actual}`);
3029
+ this.locator = locator;
3030
+ this.field = field;
3031
+ this.expected = expected;
3032
+ this.actual = actual;
3033
+ this.name = "ChecksumMismatchError";
3034
+ Object.setPrototypeOf(this, KeyVerificationError.prototype);
3035
+ }
3036
+ }
3037
+ /**
3038
+ * Computes the SHA-256 checksum of a given set of bytes.
3039
+ *
3040
+ * @param {Uint8Array} bytes - The bytes to compute the checksum of.
3041
+ */
3042
+ async function sha256Hex(bytes) {
3043
+ const hash = await crypto.subtle.digest("SHA-256", bytes);
3044
+ return Array.from(new Uint8Array(hash))
3045
+ .map((b) => b.toString(16).padStart(2, "0"))
3046
+ .join("");
3047
+ }
3048
+
3049
+ /**
3050
+ * In-memory implementation of KeyVerifier that stores and verifies key fingerprints.
3051
+ * Provides functionality to compute and verify cryptographic checksums of keys, storing them
3052
+ * in memory for subsequent verification. This implementation is primarily used for testing
3053
+ * and development purposes where persistence is not required.
3054
+ *
3055
+ * Key features:
3056
+ * - Computes SHA-256 checksums and sizes for key bytes.
3057
+ * - Stores key fingerprints in memory using string locators.
3058
+ * - Verifies key bytes against stored or provided fingerprints.
3059
+ *
3060
+ * @implements {KeyVerifier}
3061
+ */
3062
+ class MemKeyVerifier {
3063
+ keyStore = {};
3064
+ /**
3065
+ * Computes and optionally stores key metadata. If a keyFingerprint is provided, this function will verify the computed checksum against it before storing it.
3066
+ *
3067
+ * @param {KeyMetadata} keyMetadata - Object containing key bytes and optional verification data.
3068
+ * @throws {KeyVerificationError} When provided keyFingerprint doesn't match computed values.
3069
+ * @returns {Promise<KeyFingerprint>} Computed key metadata.
3070
+ */
3071
+ async computeKeyMetadata(keyMetadata) {
3072
+ // Compute the metadata from the key bytes
3073
+ const computedFingerprint = {
3074
+ checksum: await sha256Hex(keyMetadata.keyBytes),
3075
+ size: keyMetadata.keyBytes.length
3076
+ };
3077
+ // If a KeyFingerprint is provided, verify it matches computed values.
3078
+ if (keyMetadata.fingerprint) {
3079
+ if (keyMetadata.fingerprint.size !== computedFingerprint.size) {
3080
+ throw new KeyVerificationError(keyMetadata.locator ? keyMetadata.locator : "", "size", String(keyMetadata.fingerprint.size), String(computedFingerprint.size));
3081
+ }
3082
+ if (keyMetadata.fingerprint.checksum !== computedFingerprint.checksum) {
3083
+ throw new KeyVerificationError(keyMetadata.locator ? keyMetadata.locator : "", "checksum", keyMetadata.fingerprint.checksum, computedFingerprint.checksum);
3084
+ }
3085
+ }
3086
+ // If locator is provided, store only the fingerprint
3087
+ if (keyMetadata.locator) {
3088
+ this.keyStore[keyMetadata.locator] = computedFingerprint;
3089
+ }
3090
+ return computedFingerprint;
3091
+ }
3092
+ /**
3093
+ * Verifies key bytes against stored or provided metadata. Follows a priority verification scheme:
3094
+ * 1. If KeyFingerprint is provided in the metadata, this method verifies against that first.
3095
+ * 2. If a locator is provided, attempts to verify against stored fingerprint.
3096
+ * 3. If neither is available, throws an error.
3097
+ *
3098
+ * @param {KeyMetadata} keyMetadata - Object containing the key bytes and optional verification metadata.
3099
+ * @throws {Error} When neither fingerprint nor valid locator is provided for verification.
3100
+ * @throws {KeyVerificationError} When size or checksum verification fails.
3101
+ * @returns {Promise<void>} Promise that resolves when verification succeeds.
3102
+ */
3103
+ async verifyKeyBytes(keyMetadata) {
3104
+ if (!keyMetadata.keyBytes) {
3105
+ throw new Error("Key bytes must be provided for verification.");
3106
+ }
3107
+ // Compute the fingerprint for the provided bytes.
3108
+ const computedFingerprint = await this.computeKeyMetadata({
3109
+ keyBytes: keyMetadata.keyBytes
3110
+ });
3111
+ // Determine which fingerprint to verify against.
3112
+ let fingerprintToVerify;
3113
+ if (keyMetadata.fingerprint) {
3114
+ // If a key fingerprint is provided, use it.
3115
+ fingerprintToVerify = keyMetadata.fingerprint;
3116
+ }
3117
+ else if (keyMetadata.locator) {
3118
+ // Otherwise try to get stored fingerprint by locator.
3119
+ fingerprintToVerify = this.keyStore[keyMetadata.locator];
3120
+ }
3121
+ if (!fingerprintToVerify) {
3122
+ throw new Error("Either fingerprint or a valid locator must be provided for verification.");
3123
+ }
3124
+ // Verify the key size.
3125
+ if (fingerprintToVerify.size !== computedFingerprint.size) {
3126
+ throw new KeyVerificationError(keyMetadata.locator || "", "size", String(fingerprintToVerify.size), String(computedFingerprint.size));
3127
+ }
3128
+ // Verify the key checksum.
3129
+ if (fingerprintToVerify.checksum !== computedFingerprint.checksum) {
3130
+ throw new KeyVerificationError(keyMetadata.locator || "", "checksum", fingerprintToVerify.checksum, computedFingerprint.checksum);
3131
+ }
3132
+ }
3133
+ }
3134
+
3135
+ /**
3136
+ * Error thrown when a key locator is invalid for filesystem use.
3137
+ * Used to prevent path traversal and other filesystem injection when deriving paths from locators.
3138
+ *
3139
+ * @extends Error
3140
+ */
3141
+ class InvalidLocatorError extends Error {
3142
+ locator;
3143
+ reason;
3144
+ /**
3145
+ * @param message - Human-readable description of the validation failure.
3146
+ * @param locator - The invalid locator string that failed validation.
3147
+ * @param reason - Machine-readable reason code for the failure.
3148
+ */
3149
+ constructor(message, locator, reason) {
3150
+ super(message);
3151
+ this.locator = locator;
3152
+ this.reason = reason;
3153
+ this.name = "InvalidLocatorError";
3154
+ Object.setPrototypeOf(this, InvalidLocatorError.prototype);
3380
3155
  }
3381
3156
  }
3382
3157
 
@@ -5376,19 +5151,17 @@ class ProgramManager {
5376
5151
  networkClient;
5377
5152
  recordProvider;
5378
5153
  inclusionKeysLoaded = false;
5379
- _keyStore;
5380
5154
  /** Create a new instance of the ProgramManager
5381
5155
  *
5382
5156
  * @param { string | undefined } host A host uri running the official Aleo API
5383
5157
  * @param { FunctionKeyProvider | undefined } keyProvider A key provider that implements {@link FunctionKeyProvider} interface
5384
5158
  * @param { RecordProvider | undefined } recordProvider A record provider that implements {@link RecordProvider} interface
5385
5159
  */
5386
- constructor(host, keyProvider, recordProvider, networkClientOptions, keyStore) {
5160
+ constructor(host, keyProvider, recordProvider, networkClientOptions) {
5387
5161
  this.host = host ? host : "https://api.provable.com/v2";
5388
5162
  this.networkClient = new AleoNetworkClient(this.host, networkClientOptions);
5389
5163
  this.keyProvider = keyProvider ? keyProvider : new AleoKeyProvider();
5390
5164
  this.recordProvider = recordProvider;
5391
- this._keyStore = keyStore;
5392
5165
  }
5393
5166
  /**
5394
5167
  * Check if the fee is sufficient to pay for the transaction
@@ -5432,320 +5205,6 @@ class ProgramManager {
5432
5205
  setRecordProvider(recordProvider) {
5433
5206
  this.recordProvider = recordProvider;
5434
5207
  }
5435
- /**
5436
- * Set the key store for automatic key caching across executions.
5437
- *
5438
- * @param {KeyStore} keyStore
5439
- */
5440
- setKeyStore(keyStore) {
5441
- this._keyStore = keyStore;
5442
- }
5443
- /**
5444
- * Build a ProgramImportsBuilder from a program and its imports.
5445
- * Fetches imports from the network if not provided, resolves transitive
5446
- * dependencies, and optionally pre-loads cached keys from the KeyStore.
5447
- *
5448
- * @param loadKeys When true (default), loads cached proving/verifying keys
5449
- * from the KeyStore into the builder. Set to false for authorization and
5450
- * proving request paths where keys are not synthesized.
5451
- */
5452
- async buildProgramImports(program, imports, loadKeys = true) {
5453
- const builder = new ProgramImports();
5454
- const programSource = typeof program === "string" ? program : program.toString();
5455
- const programObj = Program.fromString(programSource);
5456
- const importNames = programObj.getImports();
5457
- if (importNames.length === 0 && (!imports || Object.keys(imports).length === 0)) {
5458
- return { builder, importEditions: new Map() };
5459
- }
5460
- let resolvedImports = {};
5461
- if (importNames.length > 0) {
5462
- try {
5463
- resolvedImports = await this.networkClient.getProgramImports(programSource);
5464
- }
5465
- catch (e) {
5466
- console.warn(`Failed to resolve program imports from network: ${e}. Falling back to user-provided imports.`);
5467
- }
5468
- }
5469
- if (imports) {
5470
- resolvedImports = { ...resolvedImports, ...imports };
5471
- }
5472
- // Build a map of which functions each import actually calls,
5473
- // so we only load keys for functions in the call chain.
5474
- const calledFunctions = ProgramManager.getCalledFunctions(programSource);
5475
- // Phase 1: Collect all programs via BFS, discovering transitive imports.
5476
- // The initial getProgramImports call above already resolves the full
5477
- // transitive closure via recursive DFS. The BFS loop here only needs
5478
- // to handle user-provided imports whose transitive deps may not yet be
5479
- // known. For each unknown import we issue a single getProgram() call
5480
- // (not a full recursive getProgramImports) and fetch siblings in
5481
- // parallel to minimize round-trips.
5482
- const collected = new Map();
5483
- const collectQueue = Object.entries(resolvedImports).map(([name, src]) => [name, typeof src === "string" ? src : src.toString()]);
5484
- while (collectQueue.length > 0) {
5485
- const [name, source] = collectQueue.shift();
5486
- if (collected.has(name))
5487
- continue;
5488
- collected.set(name, source);
5489
- // Discover transitive imports and collect called functions.
5490
- // Use regex instead of Program.fromString to avoid a WASM
5491
- // round-trip per import — we only need import names here.
5492
- try {
5493
- const subImports = ProgramManager.getImportNames(source);
5494
- if (subImports.length > 0) {
5495
- const transitiveCalls = ProgramManager.getCalledFunctions(source);
5496
- for (const [tProgram, tFns] of transitiveCalls) {
5497
- if (!calledFunctions.has(tProgram)) {
5498
- calledFunctions.set(tProgram, tFns);
5499
- }
5500
- else {
5501
- for (const fn of tFns)
5502
- calledFunctions.get(tProgram).add(fn);
5503
- }
5504
- }
5505
- // Fetch only unknown transitive imports — the source for
5506
- // programs already in collected/resolvedImports is known, so
5507
- // we skip them. Fetches within a BFS level run in parallel.
5508
- const unknownImports = subImports.filter((id) => !collected.has(id) && !(id in resolvedImports));
5509
- if (unknownImports.length > 0) {
5510
- const fetched = await Promise.all(unknownImports.map(async (id) => {
5511
- try {
5512
- const src = await this.networkClient.getProgram(id);
5513
- return [id, src];
5514
- }
5515
- catch {
5516
- return null;
5517
- }
5518
- }));
5519
- for (const entry of fetched) {
5520
- if (entry && !collected.has(entry[0])) {
5521
- collectQueue.push(entry);
5522
- }
5523
- }
5524
- }
5525
- }
5526
- }
5527
- catch {
5528
- // Non-blocking — transitive resolution is best-effort
5529
- }
5530
- }
5531
- // Phase 2: Add programs in topological order (leaves first).
5532
- // A simple DFS post-order ensures dependencies are added before
5533
- // dependents, regardless of the order collected entries arrived.
5534
- const sorted = [];
5535
- const visited = new Set();
5536
- const visit = (name) => {
5537
- if (visited.has(name))
5538
- return;
5539
- visited.add(name);
5540
- const source = collected.get(name);
5541
- if (!source)
5542
- return;
5543
- for (const dep of ProgramManager.getImportNames(source)) {
5544
- if (collected.has(dep))
5545
- visit(dep);
5546
- }
5547
- sorted.push([name, source]);
5548
- };
5549
- for (const [name] of collected)
5550
- visit(name);
5551
- // Resolve editions for all imports in parallel (each import may have
5552
- // a different edition than the top-level program).
5553
- const importEditions = new Map();
5554
- await Promise.all(sorted.map(async ([name]) => {
5555
- importEditions.set(name, await this.resolveEditionAndAmendment(name));
5556
- }));
5557
- for (const [name, source] of sorted) {
5558
- if (builder.contains(name))
5559
- continue;
5560
- const { edition: importEdition, amendment: importAmendment } = importEditions.get(name);
5561
- try {
5562
- builder.addProgram(name, source, importEdition);
5563
- }
5564
- catch (e) {
5565
- console.warn(`Failed to add import ${name} to builder: ${e}`);
5566
- continue;
5567
- }
5568
- if (loadKeys) {
5569
- const calledFns = calledFunctions.get(name);
5570
- await this.loadKeysFromStore(builder, name, calledFns ? [...calledFns] : [], importEdition, importAmendment);
5571
- }
5572
- }
5573
- return { builder, importEditions };
5574
- }
5575
- /**
5576
- * Extract `import program_name.aleo;` names from program source via regex.
5577
- * Avoids a WASM round-trip compared to Program.fromString + getImports.
5578
- */
5579
- static getImportNames(programSource) {
5580
- const result = [];
5581
- const importPattern = /^\s*import\s+([a-zA-Z_][a-zA-Z0-9_]*\.aleo)\s*;/gm;
5582
- let match;
5583
- while ((match = importPattern.exec(programSource)) !== null) {
5584
- result.push(match[1]);
5585
- }
5586
- return result;
5587
- }
5588
- /**
5589
- * Parse `call program.aleo/function` instructions from program source
5590
- * to determine which functions of each import are actually in the call chain.
5591
- * Returns a map of program name -> set of called function names.
5592
- */
5593
- static getCalledFunctions(programSource) {
5594
- const result = new Map();
5595
- const callPattern = /call\s+([a-zA-Z_][a-zA-Z0-9_]*\.aleo)\/([a-zA-Z_][a-zA-Z0-9_]*)/g;
5596
- let match;
5597
- while ((match = callPattern.exec(programSource)) !== null) {
5598
- const programName = match[1];
5599
- const functionName = match[2];
5600
- if (!result.has(programName)) {
5601
- result.set(programName, new Set());
5602
- }
5603
- result.get(programName).add(functionName);
5604
- }
5605
- return result;
5606
- }
5607
- /**
5608
- * Resolve the active KeyStore, preferring the directly-set _keyStore
5609
- * over the KeyProvider's keyStore().
5610
- */
5611
- async resolveKeyStore() {
5612
- if (this._keyStore)
5613
- return this._keyStore;
5614
- try {
5615
- return await this.keyProvider?.keyStore?.();
5616
- }
5617
- catch {
5618
- return undefined;
5619
- }
5620
- }
5621
- /**
5622
- * Resolve the edition and amendment count for a program from the network.
5623
- * Returns `{ edition, amendment }` or falls back to `{ edition: 1, amendment: 0 }`.
5624
- */
5625
- async resolveEditionAndAmendment(programName, fallbackEdition) {
5626
- try {
5627
- const info = await this.networkClient.getProgramAmendmentCount(programName);
5628
- return { edition: info.edition, amendment: info.amendment_count };
5629
- }
5630
- catch (e) {
5631
- console.warn(`Error finding edition/amendment for ${programName}. Network response: '${e.message}'. Defaulting to edition ${fallbackEdition ?? 1}, amendment 0.`);
5632
- return { edition: fallbackEdition ?? 1, amendment: 0 };
5633
- }
5634
- }
5635
- /**
5636
- * Load cached proving/verifying keys from the KeyStore into a ProgramImportsBuilder.
5637
- * Only loads keys for the specified functions — returns immediately if
5638
- * functionNames is empty or undefined.
5639
- * Resolves edition and amendment from the network for accurate key locator
5640
- * construction when not explicitly provided.
5641
- */
5642
- async loadKeysFromStore(builder, programName, functionNames, edition, amendment) {
5643
- if (!functionNames || functionNames.length === 0)
5644
- return;
5645
- const keyStore = await this.resolveKeyStore();
5646
- if (!keyStore)
5647
- return;
5648
- // Resolve edition and amendment from the network if not fully provided.
5649
- if (edition === undefined || amendment === undefined) {
5650
- const resolved = await this.resolveEditionAndAmendment(programName, edition);
5651
- edition = edition ?? resolved.edition;
5652
- amendment = amendment ?? resolved.amendment;
5653
- }
5654
- for (const fnName of functionNames) {
5655
- const pkLocator = provingKeyLocator(programName, fnName, edition, amendment);
5656
- const vkLocator = verifyingKeyLocator(programName, fnName, edition, amendment);
5657
- try {
5658
- const pk = await keyStore.getProvingKey(pkLocator);
5659
- if (pk)
5660
- builder.addProvingKey(programName, fnName, pk);
5661
- const vk = await keyStore.getVerifyingKey(vkLocator);
5662
- if (vk)
5663
- builder.addVerifyingKey(programName, fnName, vk);
5664
- }
5665
- catch (e) {
5666
- console.debug(`Failed to load keys for ${programName}/${fnName}: ${e}`);
5667
- }
5668
- }
5669
- }
5670
- /**
5671
- * Persist newly synthesized keys from the returned ProgramImportsBuilder
5672
- * into the KeyStore. Only writes keys that are not already in the store,
5673
- * avoiding unnecessary writes of large proving keys.
5674
- * Fetches each program's current edition and amendment count from the network
5675
- * for accurate key locator construction.
5676
- */
5677
- async persistExtractedKeys(builder, importEditions) {
5678
- const keyStore = await this.resolveKeyStore();
5679
- if (!keyStore)
5680
- return;
5681
- const programNames = Array.from(builder.programNames());
5682
- // Reuse editions resolved during buildProgramImports when available,
5683
- // falling back to parallel network resolution for any missing programs.
5684
- const editionMap = importEditions ?? new Map();
5685
- const missing = programNames.filter((name) => !editionMap.has(name));
5686
- if (missing.length > 0) {
5687
- await Promise.all(missing.map(async (name) => {
5688
- editionMap.set(name, await this.resolveEditionAndAmendment(name));
5689
- }));
5690
- }
5691
- for (const programName of programNames) {
5692
- const { edition, amendment } = editionMap.get(programName);
5693
- let fns;
5694
- try {
5695
- fns = Array.from(builder.functionKeysAvailable(programName));
5696
- }
5697
- catch (e) {
5698
- console.debug(`Failed to query keys for ${programName}: ${e}`);
5699
- continue;
5700
- }
5701
- for (const fnName of fns) {
5702
- try {
5703
- const pkLocator = provingKeyLocator(programName, fnName, edition, amendment);
5704
- const vkLocator = verifyingKeyLocator(programName, fnName, edition, amendment);
5705
- // Skip keys already in the store.
5706
- if (await keyStore.has(pkLocator) && await keyStore.has(vkLocator)) {
5707
- continue;
5708
- }
5709
- const pk = builder.getProvingKey(programName, fnName);
5710
- const vk = builder.getVerifyingKey(programName, fnName);
5711
- if (pk && vk) {
5712
- await keyStore.setKeys(pkLocator, vkLocator, [pk, vk]);
5713
- }
5714
- }
5715
- catch (e) {
5716
- console.debug(`Failed to persist key for ${programName}/${fnName}: ${e}`);
5717
- }
5718
- }
5719
- }
5720
- }
5721
- /**
5722
- * Resolve top-level function keys, checking the KeyStore first and
5723
- * falling back to the KeyProvider.
5724
- */
5725
- async resolveTopLevelKeys(programName, functionName, keySearchParams, edition, amendment) {
5726
- const keyStore = await this.resolveKeyStore();
5727
- if (keyStore) {
5728
- try {
5729
- const pkLocator = provingKeyLocator(programName, functionName, edition, amendment);
5730
- const vkLocator = verifyingKeyLocator(programName, functionName, edition, amendment);
5731
- if (await keyStore.has(pkLocator) && await keyStore.has(vkLocator)) {
5732
- const pk = await keyStore.getProvingKey(pkLocator);
5733
- const vk = await keyStore.getVerifyingKey(vkLocator);
5734
- if (pk && vk)
5735
- return [pk, vk];
5736
- }
5737
- }
5738
- catch {
5739
- // Fall through to KeyProvider
5740
- }
5741
- }
5742
- try {
5743
- return (await this.keyProvider.functionKeys(keySearchParams));
5744
- }
5745
- catch {
5746
- return undefined;
5747
- }
5748
- }
5749
5208
  /**
5750
5209
  * Set a header in the `AleoNetworkClient`s header map
5751
5210
  *
@@ -6180,9 +5639,15 @@ class ProgramManager {
6180
5639
  if (programName === undefined) {
6181
5640
  programName = programObject.id();
6182
5641
  }
6183
- const resolved = await this.resolveEditionAndAmendment(programName, edition);
6184
- edition = edition ?? resolved.edition;
6185
- const { amendment } = resolved;
5642
+ if (edition == undefined) {
5643
+ try {
5644
+ edition = await this.networkClient.getLatestProgramEdition(programName);
5645
+ }
5646
+ catch (e) {
5647
+ console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
5648
+ edition = 0;
5649
+ }
5650
+ }
6186
5651
  // Get the private key from the account if it is not provided in the parameters
6187
5652
  let executionPrivateKey = privateKey;
6188
5653
  if (typeof privateKey === "undefined" &&
@@ -6203,19 +5668,23 @@ class ProgramManager {
6203
5668
  logAndThrow(`Error finding fee keys. Key finder response: '${e.message}'. Please ensure your key provider is configured correctly.`);
6204
5669
  }
6205
5670
  const [feeProvingKey, feeVerifyingKey] = feeKeys;
6206
- // Build the ProgramImportsBuilder for import resolution and key caching.
6207
- const { builder: programImportsBuilder, importEditions } = await this.buildProgramImports(program, imports);
6208
- // Include the top-level program's already-resolved edition so
6209
- // persistExtractedKeys doesn't make a redundant network call for it.
6210
- importEditions.set(programName, { edition: edition, amendment });
6211
- // If the function proving and verifying keys are not provided, attempt to find them
5671
+ // If the function proving and verifying keys are not provided, attempt to find them using the key provider
6212
5672
  if (!provingKey || !verifyingKey) {
6213
- const keys = await this.resolveTopLevelKeys(programName, functionName, keySearchParams, edition, amendment);
6214
- if (keys) {
6215
- [provingKey, verifyingKey] = keys;
5673
+ try {
5674
+ [provingKey, verifyingKey] = (await this.keyProvider.functionKeys(keySearchParams));
6216
5675
  }
6217
- else {
6218
- console.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
5676
+ catch (e) {
5677
+ console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`);
5678
+ }
5679
+ }
5680
+ // Resolve the program imports if they exist
5681
+ const numberOfImports = programObject.getImports().length;
5682
+ if (numberOfImports > 0 && !imports) {
5683
+ try {
5684
+ imports = (await this.networkClient.getProgramImports(programName));
5685
+ }
5686
+ catch (e) {
5687
+ logAndThrow(`Error finding program imports. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`);
6219
5688
  }
6220
5689
  }
6221
5690
  // Get the fee record from the account if it is not provided in the parameters
@@ -6251,20 +5720,8 @@ class ProgramManager {
6251
5720
  }
6252
5721
  // Auto-convert bare string inputs to field elements where the function expects field type.
6253
5722
  const preparedInputs = this.prepareInputs(program, functionName, inputs);
6254
- // Build an execution transaction. Always pass the builder so synthesized
6255
- // keys (including the top-level program's) are captured via Rc<RefCell<>>
6256
- // interior mutability and can be persisted to the KeyStore.
6257
- const result = await ProgramManager$1.buildExecutionTransaction(executionPrivateKey, program, functionName, preparedInputs, priorityFee, feeRecord, this.host, undefined, // imports (legacy Object path — builder handles resolution)
6258
- provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery, edition, programImportsBuilder?.clone());
6259
- // The clone passed to WASM shares state with the original via
6260
- // Rc<RefCell<>> — synthesized keys are already visible.
6261
- try {
6262
- await this.persistExtractedKeys(programImportsBuilder, importEditions);
6263
- }
6264
- catch (e) {
6265
- console.debug(`Failed to persist extracted keys: ${e}`);
6266
- }
6267
- return result;
5723
+ // Build an execution transaction
5724
+ return await ProgramManager$1.buildExecutionTransaction(executionPrivateKey, program, functionName, preparedInputs, priorityFee, feeRecord, this.host, imports, provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery, edition);
6268
5725
  }
6269
5726
  /**
6270
5727
  * Builds an execution transaction for submission to the Aleo network from an Authorization and Fee Authorization.
@@ -6342,10 +5799,6 @@ class ProgramManager {
6342
5799
  const feeAuthorization = options.feeAuthorization;
6343
5800
  const keySearchParams = options.keySearchParams;
6344
5801
  const offlineQuery = options.offlineQuery;
6345
- let edition = options.edition;
6346
- const resolved = await this.resolveEditionAndAmendment(programName, edition);
6347
- edition = edition ?? resolved.edition;
6348
- const { amendment } = resolved;
6349
5802
  let provingKey = options.provingKey;
6350
5803
  let verifyingKey = options.verifyingKey;
6351
5804
  let program = options.program;
@@ -6374,17 +5827,24 @@ class ProgramManager {
6374
5827
  logAndThrow(`Error finding fee keys. Key finder response: '${e.message}'. Please ensure your key provider is configured correctly.`);
6375
5828
  }
6376
5829
  const [feeProvingKey, feeVerifyingKey] = feeKeys;
6377
- // Build the ProgramImportsBuilder for import resolution and key caching.
6378
- const { builder: programImportsBuilder, importEditions } = await this.buildProgramImports(program, imports);
6379
- importEditions.set(programName, { edition: edition, amendment });
6380
- // If the function proving and verifying keys are not provided, attempt to find them.
5830
+ // If the function proving and verifying keys are not provided, attempt to find them using the key provider.
6381
5831
  if (!provingKey || !verifyingKey) {
6382
- const keys = await this.resolveTopLevelKeys(programName, authorization.functionName(), keySearchParams, edition, amendment);
6383
- if (keys) {
6384
- [provingKey, verifyingKey] = keys;
5832
+ try {
5833
+ [provingKey, verifyingKey] = (await this.keyProvider.functionKeys(keySearchParams));
6385
5834
  }
6386
- else {
6387
- console.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
5835
+ catch (e) {
5836
+ console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`);
5837
+ }
5838
+ }
5839
+ // Resolve the program imports if they exist.
5840
+ console.log("Resolving program imports");
5841
+ const numberOfImports = Program.fromString(program).getImports().length;
5842
+ if (numberOfImports > 0 && !imports) {
5843
+ try {
5844
+ imports = (await this.networkClient.getProgramImports(programName));
5845
+ }
5846
+ catch (e) {
5847
+ logAndThrow(`Error finding program imports. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`);
6388
5848
  }
6389
5849
  }
6390
5850
  // If the offline query exists, add the inclusion key.
@@ -6400,20 +5860,9 @@ class ProgramManager {
6400
5860
  logAndThrow(`Inclusion key bytes not loaded, please ensure the program manager is initialized with a KeyProvider that includes the inclusion key.`);
6401
5861
  }
6402
5862
  }
6403
- // Build an execution transaction from the authorization. The
6404
- // ProgramImportsBuilder is consumed by value (ownership transfers to WASM)
6405
- // and returned enriched with any keys synthesized during execution.
6406
- const result = await ProgramManager$1.executeAuthorization(authorization, feeAuthorization, program, provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, undefined, // imports (legacy Object path — builder handles resolution)
6407
- this.host, offlineQuery, programImportsBuilder?.clone(), edition);
6408
- // The builder uses interior mutability (Rc<RefCell<>>) — synthesized
6409
- // keys are already visible through the caller's reference.
6410
- try {
6411
- await this.persistExtractedKeys(programImportsBuilder, importEditions);
6412
- }
6413
- catch (e) {
6414
- console.debug(`Failed to persist extracted keys: ${e}`);
6415
- }
6416
- return result;
5863
+ // Build an execution transaction from the authorization.
5864
+ console.log("Executing authorizations");
5865
+ return await ProgramManager$1.executeAuthorization(authorization, feeAuthorization, program, provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, imports, this.host, offlineQuery);
6417
5866
  }
6418
5867
  /**
6419
5868
  * Builds a SnarkVM `Authorization` for a specific function.
@@ -6476,17 +5925,29 @@ class ProgramManager {
6476
5925
  if (typeof executionPrivateKey === "undefined") {
6477
5926
  throw "No private key provided and no private key set in the ProgramManager";
6478
5927
  }
6479
- const resolved = await this.resolveEditionAndAmendment(programName, edition);
6480
- edition = edition ?? resolved.edition;
5928
+ if (edition == undefined) {
5929
+ try {
5930
+ edition = await this.networkClient.getLatestProgramEdition(programName);
5931
+ }
5932
+ catch (e) {
5933
+ console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
5934
+ edition = 0;
5935
+ }
5936
+ }
5937
+ // Resolve the program imports if they exist.
5938
+ const numberOfImports = Program.fromString(program).getImports().length;
5939
+ if (numberOfImports > 0 && !imports) {
5940
+ try {
5941
+ imports = (await this.networkClient.getProgramImports(programName));
5942
+ }
5943
+ catch (e) {
5944
+ logAndThrow(`Error finding program imports. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`);
5945
+ }
5946
+ }
6481
5947
  // Auto-convert bare string inputs to field elements where the function expects field type.
6482
5948
  const preparedInputs = this.prepareInputs(program, functionName, inputs);
6483
- // Build ProgramImportsBuilder for import resolution (no key loading —
6484
- // authorizations don't synthesize keys).
6485
- const { builder } = await this.buildProgramImports(program, imports, false);
6486
- const hasImports = !builder.isEmpty();
6487
5949
  // Build and return an `Authorization` for the desired function.
6488
- const authorization = await ProgramManager$1.authorize(executionPrivateKey, program, functionName, preparedInputs, hasImports ? undefined : imports, edition, hasImports ? builder?.clone() : undefined);
6489
- return authorization;
5950
+ return await ProgramManager$1.authorize(executionPrivateKey, program, functionName, preparedInputs, imports, edition);
6490
5951
  }
6491
5952
  /**
6492
5953
  * Builds a SnarkVM `Authorization` for a specific function without building a circuit first. This should be used when fast authorization generation is needed and the invoker is confident inputs are coorect.
@@ -6549,17 +6010,29 @@ class ProgramManager {
6549
6010
  if (typeof executionPrivateKey === "undefined") {
6550
6011
  throw "No private key provided and no private key set in the ProgramManager";
6551
6012
  }
6552
- const resolved = await this.resolveEditionAndAmendment(programName, edition);
6553
- edition = edition ?? resolved.edition;
6013
+ // Resolve the program imports if they exist.
6014
+ const numberOfImports = Program.fromString(program).getImports().length;
6015
+ if (numberOfImports > 0 && !imports) {
6016
+ try {
6017
+ imports = (await this.networkClient.getProgramImports(programName));
6018
+ }
6019
+ catch (e) {
6020
+ logAndThrow(`Error finding program imports. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`);
6021
+ }
6022
+ }
6023
+ if (edition == undefined) {
6024
+ try {
6025
+ edition = await this.networkClient.getLatestProgramEdition(programName);
6026
+ }
6027
+ catch (e) {
6028
+ console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
6029
+ edition = 0;
6030
+ }
6031
+ }
6554
6032
  // Auto-convert bare string inputs to field elements where the function expects field type.
6555
6033
  const preparedInputs = this.prepareInputs(program, functionName, inputs);
6556
- // Build ProgramImportsBuilder for import resolution (no key loading —
6557
- // authorizations don't synthesize keys).
6558
- const { builder } = await this.buildProgramImports(program, imports, false);
6559
- const hasImports = !builder.isEmpty();
6560
6034
  // Build and return an `Authorization` for the desired function.
6561
- const authorization = await ProgramManager$1.buildAuthorizationUnchecked(executionPrivateKey, program, functionName, preparedInputs, hasImports ? undefined : imports, edition, hasImports ? builder?.clone() : undefined);
6562
- return authorization;
6035
+ return await ProgramManager$1.buildAuthorizationUnchecked(executionPrivateKey, program, functionName, preparedInputs, imports, edition);
6563
6036
  }
6564
6037
  /**
6565
6038
  * Builds a `ProvingRequest` for submission to a prover for execution. If building a proving request with an ExecutionRequest, a private key must be explicitly provided.
@@ -6622,8 +6095,15 @@ class ProgramManager {
6622
6095
  if (programName === undefined) {
6623
6096
  programName = Program.fromString(program).id();
6624
6097
  }
6625
- const resolved = await this.resolveEditionAndAmendment(programName, edition);
6626
- edition = edition ?? resolved.edition;
6098
+ if (edition == undefined) {
6099
+ try {
6100
+ edition = await this.networkClient.getLatestProgramEdition(programName);
6101
+ }
6102
+ catch (e) {
6103
+ console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
6104
+ edition = 0;
6105
+ }
6106
+ }
6627
6107
  // Get the private key from the account if it is not provided in the parameters.
6628
6108
  let executionPrivateKey = privateKey;
6629
6109
  if (typeof privateKey === "undefined" &&
@@ -6661,30 +6141,8 @@ class ProgramManager {
6661
6141
  catch (e) {
6662
6142
  logAndThrow(`Error finding fee record. Record finder response: '${e.message}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`);
6663
6143
  }
6664
- // Build ProgramImportsBuilder for import resolution (no key loading —
6665
- // proving requests don't synthesize keys).
6666
- // Note: imports is kept for the Rust-side fee estimation fallback
6667
- // (estimate_fee_for_authorization uses the legacy imports Object to avoid
6668
- // a RefCell double-borrow — see proving_request.rs).
6669
- const { builder } = await this.buildProgramImports(program, imports, false);
6670
- const hasImports = !builder.isEmpty();
6671
- // Normalize imports to the full merged set from the builder so the
6672
- // Rust fee estimator sees all transitive imports, not just the
6673
- // caller's partial set. Use programNames + getProgram to avoid
6674
- // serializing key bytes (toObject would serialize all proving/
6675
- // verifying keys, which can be tens of MB).
6676
- if (hasImports) {
6677
- const merged = {};
6678
- for (const name of Array.from(builder.programNames())) {
6679
- const src = builder.getProgram(name);
6680
- if (src)
6681
- merged[name] = src;
6682
- }
6683
- imports = merged;
6684
- }
6685
6144
  if (options.executionRequest instanceof ExecutionRequest) {
6686
- return await ProgramManager$1.buildProvingRequestFromExecutionRequest(options.executionRequest, program, unchecked, broadcast, edition, imports, // kept for fee estimation in Rust
6687
- executionPrivateKey, hasImports ? builder?.clone() : undefined);
6145
+ return await ProgramManager$1.buildProvingRequestFromExecutionRequest(options.executionRequest, program, unchecked, broadcast, edition, imports, executionPrivateKey);
6688
6146
  }
6689
6147
  else {
6690
6148
  // Ensure the private key exists.
@@ -6698,8 +6156,7 @@ class ProgramManager {
6698
6156
  // Auto-convert bare string inputs to field elements where the function expects field type.
6699
6157
  const preparedInputs = this.prepareInputs(program, functionName, inputs);
6700
6158
  // Build and return the `ProvingRequest`.
6701
- return await ProgramManager$1.buildProvingRequest(executionPrivateKey, program, functionName, preparedInputs, baseFee, priorityFee, feeRecord, imports, // kept for fee estimation in Rust
6702
- broadcast, unchecked, edition, useFeeMaster, hasImports ? builder?.clone() : undefined);
6159
+ return await ProgramManager$1.buildProvingRequest(executionPrivateKey, program, functionName, preparedInputs, baseFee, priorityFee, feeRecord, imports, broadcast, unchecked, edition, useFeeMaster);
6703
6160
  }
6704
6161
  }
6705
6162
  /**
@@ -6872,10 +6329,6 @@ class ProgramManager {
6872
6329
  * assert(result === ["10u32"]);
6873
6330
  */
6874
6331
  async run(program, function_name, inputs, proveExecution, imports, keySearchParams, provingKey, verifyingKey, privateKey, offlineQuery, edition) {
6875
- const programName = Program.fromString(program).id();
6876
- const resolved = await this.resolveEditionAndAmendment(programName, edition);
6877
- edition = edition ?? resolved.edition;
6878
- const { amendment } = resolved;
6879
6332
  // Get the private key from the account if it is not provided in the parameters
6880
6333
  let executionPrivateKey = privateKey;
6881
6334
  if (typeof privateKey === "undefined" &&
@@ -6885,33 +6338,22 @@ class ProgramManager {
6885
6338
  if (typeof executionPrivateKey === "undefined") {
6886
6339
  throw "No private key provided and no private key set in the ProgramManager";
6887
6340
  }
6888
- // Build the ProgramImportsBuilder for import resolution and key caching.
6889
- const { builder, importEditions } = await this.buildProgramImports(program, imports);
6890
- importEditions.set(programName, { edition: edition, amendment });
6341
+ // If the function proving and verifying keys are not provided, attempt to find them using the key provider
6891
6342
  if (!provingKey || !verifyingKey) {
6892
- const keys = await this.resolveTopLevelKeys(programName, function_name, keySearchParams, edition, amendment);
6893
- if (keys) {
6894
- [provingKey, verifyingKey] = keys;
6343
+ try {
6344
+ [provingKey, verifyingKey] = (await this.keyProvider.functionKeys(keySearchParams));
6895
6345
  }
6896
- else {
6897
- console.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
6346
+ catch (e) {
6347
+ console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`);
6898
6348
  }
6899
6349
  }
6900
6350
  // Auto-convert bare string inputs to field elements where the function expects field type.
6901
6351
  const preparedInputs = this.prepareInputs(program, function_name, inputs);
6902
- // Run the program offline. Always pass the builder so synthesized
6903
- // keys (including the top-level program's) are captured and persisted.
6904
- const result = await ProgramManager$1.executeFunctionOffline(executionPrivateKey, program, function_name, preparedInputs, proveExecution, false, undefined, // imports (legacy Object path — builder handles resolution)
6905
- provingKey, verifyingKey, this.host, offlineQuery, edition, builder?.clone());
6906
- // The clone passed to WASM shares state with the original via
6907
- // Rc<RefCell<>> — synthesized keys are already visible.
6908
- try {
6909
- await this.persistExtractedKeys(builder, importEditions);
6910
- }
6911
- catch (e) {
6912
- console.debug(`Failed to persist extracted keys: ${e}`);
6913
- }
6914
- return result;
6352
+ // Run the program offline and return the result
6353
+ console.log("Running program offline");
6354
+ console.log("Proving key: ", provingKey);
6355
+ console.log("Verifying key: ", verifyingKey);
6356
+ return ProgramManager$1.executeFunctionOffline(executionPrivateKey, program, function_name, preparedInputs, proveExecution, false, imports, provingKey, verifyingKey, this.host, offlineQuery, edition);
6915
6357
  }
6916
6358
  /**
6917
6359
  * Join two credits records into a single credits record
@@ -8013,8 +7455,12 @@ class ProgramManager {
8013
7455
  throw new Error("Authorization must be provided if estimating fee for Authorization.");
8014
7456
  }
8015
7457
  const programSource = program ? program.toString() : await this.networkClient.getProgram(programName, edition);
8016
- const programImports = imports ?? await this.networkClient.getProgramImports(programSource);
8017
- return ProgramManager$1.estimateFeeForAuthorization(authorization, programSource, programImports, edition);
7458
+ const programImports = imports ? imports : await this.networkClient.getProgramImports(programSource);
7459
+ console.log(JSON.stringify(programImports));
7460
+ if (Object.keys(programImports)) {
7461
+ return ProgramManager$1.estimateFeeForAuthorization(authorization, programSource, programImports, edition);
7462
+ }
7463
+ return ProgramManager$1.estimateFeeForAuthorization(authorization, programSource, imports, edition);
8018
7464
  }
8019
7465
  /**
8020
7466
  * Estimate the execution fee for an Aleo function.
@@ -8160,8 +7606,15 @@ class ProgramManager {
8160
7606
  if (programName === undefined) {
8161
7607
  programName = programObject.id();
8162
7608
  }
8163
- const resolved = await this.resolveEditionAndAmendment(programName, edition);
8164
- edition = edition ?? resolved.edition;
7609
+ if (edition == undefined) {
7610
+ try {
7611
+ edition = await this.networkClient.getLatestProgramEdition(programName);
7612
+ }
7613
+ catch (e) {
7614
+ console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
7615
+ edition = 0;
7616
+ }
7617
+ }
8165
7618
  // Get the private key from the account if it is not provided in the parameters.
8166
7619
  let executionPrivateKey = privateKey;
8167
7620
  if (typeof privateKey === "undefined" &&
@@ -8746,5 +8199,5 @@ async function initializeWasm() {
8746
8199
  console.warn("initializeWasm is deprecated, you no longer need to use it");
8747
8200
  }
8748
8201
 
8749
- export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KeyVerificationError as ChecksumMismatchError, DecryptionNotEnabledError, IndexedDBKeyStore, InvalidLocatorError, KEY_STORE, KeyVerificationError, MemKeyVerifier, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TO_PRIVATE_TRANSFER, PUBLIC_TRANSFER, PUBLIC_TRANSFER_AS_SIGNER, ProgramManager, RECORD_DOMAIN, RecordNotFoundError, RecordScanner, RecordScannerRequestError, SealanceMerkleTree, UUIDError, VALID_TRANSFER_TYPES, ViewKeyNotStoredError, buildExecutionRequestFromExternallySignedData, computeExternalSigningInputs, encryptAuthorization, encryptProvingRequest, encryptRegistrationRequest, encryptViewKey, initializeWasm, inputsToFields, isInputIdStrategy, isProveApiErrorBody, isProvingResponse, isRecordViewKeyStrategy, isViewKeyStrategy, logAndThrow, provingKeyLocator, sha256Hex, toAddress, toField, toGroup, toSignature, toViewKey, translationKeyLocator, verifyBatchProof, verifyProof, verifyingKeyLocator, zeroizeBytes };
8202
+ export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KeyVerificationError as ChecksumMismatchError, DecryptionNotEnabledError, InvalidLocatorError, KEY_STORE, KeyVerificationError, MemKeyVerifier, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TO_PRIVATE_TRANSFER, PUBLIC_TRANSFER, PUBLIC_TRANSFER_AS_SIGNER, ProgramManager, RECORD_DOMAIN, RecordNotFoundError, RecordScanner, RecordScannerRequestError, SealanceMerkleTree, UUIDError, VALID_TRANSFER_TYPES, ViewKeyNotStoredError, buildExecutionRequestFromExternallySignedData, computeExternalSigningInputs, encryptAuthorization, encryptProvingRequest, encryptRegistrationRequest, encryptViewKey, initializeWasm, inputsToFields, isInputIdStrategy, isProveApiErrorBody, isProvingResponse, isRecordViewKeyStrategy, isViewKeyStrategy, logAndThrow, provingKeyLocator, sha256Hex, toAddress, toField, toGroup, toSignature, toViewKey, translationKeyLocator, verifyBatchProof, verifyProof, verifyingKeyLocator, zeroizeBytes };
8750
8203
  //# sourceMappingURL=browser.js.map