@provablehq/sdk 0.8.8 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,38 @@
1
1
  import { PrivateKey, RecordCiphertext, Program, Plaintext, Address, Transaction, Metadata, VerifyingKey, ProvingKey, ProgramManager as ProgramManager$1, RecordPlaintext, verifyFunctionExecution } from '@provablehq/wasm/testnet.js';
2
2
 
3
+ function detectBrowser() {
4
+ const userAgent = navigator.userAgent;
5
+ if (/chrome|crios|crmo/i.test(userAgent) && !/edge|edg|opr/i.test(userAgent)) {
6
+ return "chrome";
7
+ }
8
+ else if (/firefox|fxios/i.test(userAgent)) {
9
+ return "firefox";
10
+ }
11
+ else if (/safari/i.test(userAgent) && !/chrome|crios|crmo|android/i.test(userAgent)) {
12
+ return "safari";
13
+ }
14
+ else if (/edg/i.test(userAgent)) {
15
+ return "edge";
16
+ }
17
+ else if (/opr\//i.test(userAgent)) {
18
+ return "opera";
19
+ }
20
+ else {
21
+ return "browser";
22
+ }
23
+ }
24
+ function environment() {
25
+ if ((typeof process !== 'undefined') &&
26
+ (process.release?.name === 'node')) {
27
+ return 'node';
28
+ }
29
+ else if (typeof window !== 'undefined') {
30
+ return detectBrowser();
31
+ }
32
+ else {
33
+ return 'unknown';
34
+ }
35
+ }
3
36
  function logAndThrow(message) {
4
37
  console.error(message);
5
38
  throw new Error(message);
@@ -30,6 +63,37 @@ async function post(url, options) {
30
63
  }
31
64
  return response;
32
65
  }
66
+ async function retryWithBackoff(fn, { maxAttempts = 5, baseDelay = 100, jitter, retryOnStatus = [], shouldRetry, } = {}) {
67
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
68
+ try {
69
+ return await fn();
70
+ }
71
+ catch (err) {
72
+ const isLast = attempt === maxAttempts;
73
+ const error = err;
74
+ let retryable = false;
75
+ if (typeof error.status === "number") {
76
+ if (error.status >= 500) {
77
+ retryable = true;
78
+ }
79
+ else if (error.status >= 400 && shouldRetry) {
80
+ retryable = shouldRetry(error);
81
+ }
82
+ }
83
+ else if (shouldRetry) {
84
+ retryable = shouldRetry(error);
85
+ }
86
+ if (!retryable || isLast)
87
+ throw error;
88
+ const jitterAmount = jitter ?? baseDelay;
89
+ const actualJitter = Math.floor(Math.random() * jitterAmount);
90
+ const delay = baseDelay * 2 ** (attempt - 1) + actualJitter;
91
+ console.warn(`Retry ${attempt}/${maxAttempts} failed. Retrying in ${delay}ms...`);
92
+ await new Promise((res) => setTimeout(res, delay));
93
+ }
94
+ }
95
+ throw new Error("retryWithBackoff: unreachable");
96
+ }
33
97
 
34
98
  /**
35
99
  * Client library that encapsulates REST calls to publicly exposed endpoints of Aleo nodes. The methods provided in this
@@ -48,15 +112,20 @@ class AleoNetworkClient {
48
112
  host;
49
113
  headers;
50
114
  account;
115
+ ctx;
116
+ network;
51
117
  constructor(host, options) {
52
118
  this.host = host + "/testnet";
119
+ this.network = "testnet";
120
+ this.ctx = {};
53
121
  if (options && options.headers) {
54
122
  this.headers = options.headers;
55
123
  }
56
124
  else {
57
125
  this.headers = {
58
126
  // This is replaced by the actual version by a Rollup plugin
59
- "X-Aleo-SDK-Version": "0.8.8",
127
+ "X-Aleo-SDK-Version": "0.9.1",
128
+ "X-Aleo-environment": environment(),
60
129
  };
61
130
  }
62
131
  }
@@ -101,6 +170,41 @@ class AleoNetworkClient {
101
170
  setHost(host) {
102
171
  this.host = host + "/testnet";
103
172
  }
173
+ /**
174
+ * Set a header in the `AleoNetworkClient`s header map
175
+ *
176
+ * @param {string} headerName The name of the header to set
177
+ * @param {string} value The header value
178
+ *
179
+ * @example
180
+ * import { AleoNetworkClient } from "@provablehq/sdk/mainnet.js";
181
+ *
182
+ * // Create a networkClient
183
+ * const networkClient = new AleoNetworkClient();
184
+ *
185
+ * // Set the value of the `Accept-Language` header to `en-US`
186
+ * networkClient.setHeader('Accept-Language', 'en-US');
187
+ */
188
+ setHeader(headerName, value) {
189
+ this.headers[headerName] = value;
190
+ }
191
+ /**
192
+ * Remove a header from the `AleoNetworkClient`s header map
193
+ *
194
+ * @param {string} headerName The name of the header to be removed
195
+ *
196
+ * @example
197
+ * import { AleoNetworkClient } from "@provablehq/sdk/mainnet.js";
198
+ *
199
+ * // Create a networkClient
200
+ * const networkClient = new AleoNetworkClient();
201
+ *
202
+ * // Remove the default `X-Aleo-SDK-Version` header
203
+ * networkClient.removeHeader('X-Aleo-SDK-Version');
204
+ */
205
+ removeHeader(headerName) {
206
+ delete this.headers[headerName];
207
+ }
104
208
  /**
105
209
  * Fetches data from the Aleo network and returns it as a JSON object.
106
210
  *
@@ -108,7 +212,8 @@ class AleoNetworkClient {
108
212
  */
109
213
  async fetchData(url = "/") {
110
214
  try {
111
- return parseJSON(await this.fetchRaw(url));
215
+ const raw = await this.fetchRaw(url);
216
+ return parseJSON(raw);
112
217
  }
113
218
  catch (error) {
114
219
  throw new Error(`Error fetching data: ${error}`);
@@ -124,15 +229,31 @@ class AleoNetworkClient {
124
229
  */
125
230
  async fetchRaw(url = "/") {
126
231
  try {
127
- const response = await get(this.host + url, {
128
- headers: this.headers
232
+ const ctx = { ...this.ctx };
233
+ return await retryWithBackoff(async () => {
234
+ const response = await get(this.host + url, {
235
+ headers: {
236
+ ...this.headers,
237
+ ...ctx,
238
+ },
239
+ });
240
+ return await response.text();
129
241
  });
130
- return await response.text();
131
242
  }
132
243
  catch (error) {
133
244
  throw new Error(`Error fetching data: ${error}`);
134
245
  }
135
246
  }
247
+ /**
248
+ * Wrapper around the POST helper to allow mocking in tests. Not meant for use in production.
249
+ *
250
+ * @param url The URL to POST to.
251
+ * @param options The RequestInit options for the POST request.
252
+ * @returns The Response object from the POST request.
253
+ */
254
+ async _sendPost(url, options) {
255
+ return post(url, options);
256
+ }
136
257
  /**
137
258
  * Attempt to find records in the Aleo blockchain.
138
259
  *
@@ -190,7 +311,10 @@ class AleoNetworkClient {
190
311
  }
191
312
  else {
192
313
  try {
193
- resolvedPrivateKey = privateKey instanceof PrivateKey ? privateKey : PrivateKey.from_string(privateKey);
314
+ resolvedPrivateKey =
315
+ privateKey instanceof PrivateKey
316
+ ? privateKey
317
+ : PrivateKey.from_string(privateKey);
194
318
  }
195
319
  catch (error) {
196
320
  throw new Error("Error parsing private key provided.");
@@ -241,8 +365,12 @@ class AleoNetworkClient {
241
365
  // Search for unspent records in execute transactions of credits.aleo
242
366
  if (confirmedTransaction.type == "execute") {
243
367
  const transaction = confirmedTransaction.transaction;
244
- if (transaction.execution && !(typeof transaction.execution.transitions == "undefined")) {
245
- for (let k = 0; k < transaction.execution.transitions.length; k++) {
368
+ if (transaction.execution &&
369
+ !(typeof transaction.execution
370
+ .transitions == "undefined")) {
371
+ for (let k = 0; k <
372
+ transaction.execution.transitions
373
+ .length; k++) {
246
374
  const transition = transaction.execution.transitions[k];
247
375
  // Only search for unspent records in the specified programs.
248
376
  if (!(typeof programs === "undefined")) {
@@ -250,7 +378,8 @@ class AleoNetworkClient {
250
378
  continue;
251
379
  }
252
380
  }
253
- if (!(typeof transition.outputs == "undefined")) {
381
+ if (!(typeof transition.outputs ==
382
+ "undefined")) {
254
383
  for (let l = 0; l < transition.outputs.length; l++) {
255
384
  const output = transition.outputs[l];
256
385
  if (output.type === "record") {
@@ -271,7 +400,7 @@ class AleoNetworkClient {
271
400
  const serialNumber = recordPlaintext.serialNumberString(resolvedPrivateKey, "credits.aleo", "credits");
272
401
  // Attempt to see if the serial number is spent
273
402
  try {
274
- await this.getTransitionId(serialNumber);
403
+ await retryWithBackoff(() => this.getTransitionId(serialNumber));
275
404
  continue;
276
405
  }
277
406
  catch (error) {
@@ -282,37 +411,47 @@ class AleoNetworkClient {
282
411
  if (!amounts) {
283
412
  records.push(recordPlaintext);
284
413
  // If the user specified a maximum number of microcredits, check if the search has found enough
285
- if (typeof maxMicrocredits === "number") {
286
- totalRecordValue += recordPlaintext.microcredits();
414
+ if (typeof maxMicrocredits ===
415
+ "number") {
416
+ totalRecordValue +=
417
+ recordPlaintext.microcredits();
287
418
  // Exit if the search has found the amount specified
288
- if (totalRecordValue >= BigInt(maxMicrocredits)) {
419
+ if (totalRecordValue >=
420
+ BigInt(maxMicrocredits)) {
289
421
  return records;
290
422
  }
291
423
  }
292
424
  }
293
425
  // If the user specified a list of amounts, check if the search has found them
294
- if (!(typeof amounts === "undefined") && amounts.length > 0) {
426
+ if (!(typeof amounts ===
427
+ "undefined") &&
428
+ amounts.length >
429
+ 0) {
295
430
  let amounts_found = 0;
296
- if (recordPlaintext.microcredits() > amounts[amounts_found]) {
431
+ if (recordPlaintext.microcredits() >
432
+ amounts[amounts_found]) {
297
433
  amounts_found += 1;
298
434
  records.push(recordPlaintext);
299
435
  // If the user specified a maximum number of microcredits, check if the search has found enough
300
- if (typeof maxMicrocredits === "number") {
301
- totalRecordValue += recordPlaintext.microcredits();
436
+ if (typeof maxMicrocredits ===
437
+ "number") {
438
+ totalRecordValue +=
439
+ recordPlaintext.microcredits();
302
440
  // Exit if the search has found the amount specified
303
- if (totalRecordValue >= BigInt(maxMicrocredits)) {
441
+ if (totalRecordValue >=
442
+ BigInt(maxMicrocredits)) {
304
443
  return records;
305
444
  }
306
445
  }
307
- if (records.length >= amounts.length) {
446
+ if (records.length >=
447
+ amounts.length) {
308
448
  return records;
309
449
  }
310
450
  }
311
451
  }
312
452
  }
313
453
  }
314
- catch (error) {
315
- }
454
+ catch (error) { }
316
455
  }
317
456
  }
318
457
  }
@@ -325,7 +464,10 @@ class AleoNetworkClient {
325
464
  }
326
465
  catch (error) {
327
466
  // If there is an error fetching blocks, log it and keep searching
328
- console.warn("Error fetching blocks in range: " + start.toString() + "-" + end.toString());
467
+ console.warn("Error fetching blocks in range: " +
468
+ start.toString() +
469
+ "-" +
470
+ end.toString());
329
471
  console.warn("Error: ", error);
330
472
  failures += 1;
331
473
  if (failures > 10) {
@@ -368,7 +510,16 @@ class AleoNetworkClient {
368
510
  * const records = networkClient.findUnspentRecords(startHeight, undefined, ["credits.aleo"], undefined, maxMicrocredits);
369
511
  */
370
512
  async findUnspentRecords(startHeight, endHeight, programs, amounts, maxMicrocredits, nonces, privateKey) {
371
- return await this.findRecords(startHeight, endHeight, true, programs, amounts, maxMicrocredits, nonces, privateKey);
513
+ try {
514
+ this.ctx = { "X-ALEO-METHOD": "findUnspentRecords" };
515
+ return await this.findRecords(startHeight, endHeight, true, programs, amounts, maxMicrocredits, nonces, privateKey);
516
+ }
517
+ catch (error) {
518
+ throw new Error("Error finding unspent records: " + error);
519
+ }
520
+ finally {
521
+ this.ctx = {};
522
+ }
372
523
  }
373
524
  /**
374
525
  * Returns the contents of the block at the specified block height.
@@ -381,12 +532,16 @@ class AleoNetworkClient {
381
532
  */
382
533
  async getBlock(blockHeight) {
383
534
  try {
535
+ this.ctx = { "X-ALEO-METHOD": "getBlock" };
384
536
  const block = await this.fetchData("/block/" + blockHeight);
385
537
  return block;
386
538
  }
387
539
  catch (error) {
388
540
  throw new Error(`Error fetching block ${blockHeight}: ${error}`);
389
541
  }
542
+ finally {
543
+ this.ctx = {};
544
+ }
390
545
  }
391
546
  /**
392
547
  * Returns the contents of the block with the specified hash.
@@ -402,12 +557,16 @@ class AleoNetworkClient {
402
557
  */
403
558
  async getBlockByHash(blockHash) {
404
559
  try {
560
+ this.ctx = { "X-ALEO-METHOD": "getBlockByHash" };
405
561
  const block = await this.fetchData(`/block/${blockHash}`);
406
562
  return block;
407
563
  }
408
564
  catch (error) {
409
565
  throw new Error(`Error fetching block ${blockHash}: ${error}`);
410
566
  }
567
+ finally {
568
+ this.ctx = {};
569
+ }
411
570
  }
412
571
  /**
413
572
  * Returns a range of blocks between the specified block heights. A maximum of 50 blocks can be fetched at a time.
@@ -431,11 +590,15 @@ class AleoNetworkClient {
431
590
  */
432
591
  async getBlockRange(start, end) {
433
592
  try {
593
+ this.ctx = { "X-ALEO-METHOD": "getBlockRange" };
434
594
  return await this.fetchData("/blocks?start=" + start + "&end=" + end);
435
595
  }
436
596
  catch (error) {
437
597
  throw new Error(`Error fetching blocks between ${start} and ${end}: ${error}`);
438
598
  }
599
+ finally {
600
+ this.ctx = {};
601
+ }
439
602
  }
440
603
  /**
441
604
  * Returns the deployment transaction id associated with the specified program.
@@ -457,16 +620,20 @@ class AleoNetworkClient {
457
620
  * const verifyingKeys = transaction.verifyingKeys();
458
621
  */
459
622
  async getDeploymentTransactionIDForProgram(program) {
623
+ this.ctx = { "X-ALEO-METHOD": "getDeploymentTransactionIDForProgram" };
460
624
  if (program instanceof Program) {
461
625
  program = program.id();
462
626
  }
463
627
  try {
464
628
  const id = await this.fetchData("/find/transactionID/deployment/" + program);
465
- return id.replace("\"", "");
629
+ return id.replace('"', "");
466
630
  }
467
631
  catch (error) {
468
632
  throw new Error(`Error fetching deployment transaction for program ${program}: ${error}`);
469
633
  }
634
+ finally {
635
+ this.ctx = {};
636
+ }
470
637
  }
471
638
  /**
472
639
  * Returns the deployment transaction associated with a specified program as a JSON object.
@@ -490,12 +657,16 @@ class AleoNetworkClient {
490
657
  program = program.id();
491
658
  }
492
659
  try {
493
- const transaction_id = await this.getDeploymentTransactionIDForProgram(program);
660
+ this.ctx = { "X-ALEO-METHOD": "getDeploymentTransactionForProgram" };
661
+ const transaction_id = (await this.getDeploymentTransactionIDForProgram(program));
494
662
  return await this.getTransaction(transaction_id);
495
663
  }
496
664
  catch (error) {
497
665
  throw new Error(`Error fetching deployment transaction for program ${program}: ${error}`);
498
666
  }
667
+ finally {
668
+ this.ctx = {};
669
+ }
499
670
  }
500
671
  /**
501
672
  * Returns the deployment transaction associated with a specified program as a wasm object.
@@ -518,12 +689,16 @@ class AleoNetworkClient {
518
689
  */
519
690
  async getDeploymentTransactionObjectForProgram(program) {
520
691
  try {
521
- const transaction_id = await this.getDeploymentTransactionIDForProgram(program);
692
+ this.ctx = { "X-ALEO-METHOD": "getDeploymentTransactionObjectForProgram" };
693
+ const transaction_id = (await this.getDeploymentTransactionIDForProgram(program));
522
694
  return await this.getTransactionObject(transaction_id);
523
695
  }
524
696
  catch (error) {
525
697
  throw new Error(`Error fetching deployment transaction for program ${program}: ${error}`);
526
698
  }
699
+ finally {
700
+ this.ctx = {};
701
+ }
527
702
  }
528
703
  /**
529
704
  * Returns the contents of the latest block as JSON.
@@ -540,11 +715,15 @@ class AleoNetworkClient {
540
715
  */
541
716
  async getLatestBlock() {
542
717
  try {
543
- return await this.fetchData("/block/latest");
718
+ this.ctx = { "X-ALEO-METHOD": "getLatestBlock" };
719
+ return (await this.fetchData("/block/latest"));
544
720
  }
545
721
  catch (error) {
546
722
  throw new Error(`Error fetching latest block: ${error}`);
547
723
  }
724
+ finally {
725
+ this.ctx = {};
726
+ }
548
727
  }
549
728
  /**
550
729
  * Returns the latest committee.
@@ -563,11 +742,15 @@ class AleoNetworkClient {
563
742
  */
564
743
  async getLatestCommittee() {
565
744
  try {
745
+ this.ctx = { "X-ALEO-METHOD": "getLatestCommittee" };
566
746
  return await this.fetchData("/committee/latest");
567
747
  }
568
748
  catch (error) {
569
749
  throw new Error(`Error fetching latest committee: ${error}`);
570
750
  }
751
+ finally {
752
+ this.ctx = {};
753
+ }
571
754
  }
572
755
  /**
573
756
  * Returns the committee at the specified block height.
@@ -587,11 +770,15 @@ class AleoNetworkClient {
587
770
  */
588
771
  async getCommitteeByBlockHeight(blockHeight) {
589
772
  try {
773
+ this.ctx = { "X-ALEO-METHOD": "getCommitteeByBlockHeight" };
590
774
  return await this.fetchData(`/committee/${blockHeight}`);
591
775
  }
592
776
  catch (error) {
593
777
  throw new Error(`Error fetching committee at height ${blockHeight}: ${error}`);
594
778
  }
779
+ finally {
780
+ this.ctx = {};
781
+ }
595
782
  }
596
783
  /**
597
784
  * Returns the latest block height.
@@ -608,11 +795,15 @@ class AleoNetworkClient {
608
795
  */
609
796
  async getLatestHeight() {
610
797
  try {
798
+ this.ctx = { "X-ALEO-METHOD": "getLatestHeight" };
611
799
  return Number(await this.fetchData("/block/height/latest"));
612
800
  }
613
801
  catch (error) {
614
802
  throw new Error(`Error fetching latest height: ${error}`);
615
803
  }
804
+ finally {
805
+ this.ctx = {};
806
+ }
616
807
  }
617
808
  /**
618
809
  * Returns the latest block hash.
@@ -630,11 +821,15 @@ class AleoNetworkClient {
630
821
  */
631
822
  async getLatestBlockHash() {
632
823
  try {
824
+ this.ctx = { "X-ALEO-METHOD": "getLatestBlockHash" };
633
825
  return String(await this.fetchData("/block/hash/latest"));
634
826
  }
635
827
  catch (error) {
636
828
  throw new Error(`Error fetching latest hash: ${error}`);
637
829
  }
830
+ finally {
831
+ this.ctx = {};
832
+ }
638
833
  }
639
834
  /**
640
835
  * Returns the source code of a program given a program ID.
@@ -654,11 +849,15 @@ class AleoNetworkClient {
654
849
  */
655
850
  async getProgram(programId) {
656
851
  try {
852
+ this.ctx = { "X-ALEO-METHOD": "getProgram" };
657
853
  return await this.fetchData("/program/" + programId);
658
854
  }
659
855
  catch (error) {
660
856
  throw new Error(`Error fetching program ${programId}: ${error}`);
661
857
  }
858
+ finally {
859
+ this.ctx = {};
860
+ }
662
861
  }
663
862
  /**
664
863
  * Returns a program object from a program ID or program source code.
@@ -684,16 +883,20 @@ class AleoNetworkClient {
684
883
  */
685
884
  async getProgramObject(inputProgram) {
686
885
  try {
886
+ this.ctx = { "X-ALEO-METHOD": "getProgramObject" };
687
887
  return Program.fromString(inputProgram);
688
888
  }
689
889
  catch (error) {
690
890
  try {
691
- return Program.fromString((await this.getProgram(inputProgram)));
891
+ return Program.fromString(await this.getProgram(inputProgram));
692
892
  }
693
893
  catch (error) {
694
894
  throw new Error(`${inputProgram} is neither a program name or a valid program: ${error}`);
695
895
  }
696
896
  }
897
+ finally {
898
+ this.ctx = {};
899
+ }
697
900
  }
698
901
  /**
699
902
  * Returns an object containing the source code of a program and the source code of all programs it imports
@@ -727,17 +930,20 @@ class AleoNetworkClient {
727
930
  */
728
931
  async getProgramImports(inputProgram) {
729
932
  try {
933
+ this.ctx = { "X-ALEO-METHOD": "getProgramImports" };
730
934
  const imports = {};
731
935
  // Get the program object or fail if the program is not valid or does not exist
732
- const program = inputProgram instanceof Program ? inputProgram : (await this.getProgramObject(inputProgram));
936
+ const program = inputProgram instanceof Program
937
+ ? inputProgram
938
+ : await this.getProgramObject(inputProgram);
733
939
  // Get the list of programs that the program imports
734
940
  const importList = program.getImports();
735
941
  // Recursively get any imports that the imported programs have in a depth first search order
736
942
  for (let i = 0; i < importList.length; i++) {
737
943
  const import_id = importList[i];
738
944
  if (!imports.hasOwnProperty(import_id)) {
739
- const programSource = await this.getProgram(import_id);
740
- const nestedImports = await this.getProgramImports(import_id);
945
+ const programSource = (await this.getProgram(import_id));
946
+ const nestedImports = (await this.getProgramImports(import_id));
741
947
  for (const key in nestedImports) {
742
948
  if (!imports.hasOwnProperty(key)) {
743
949
  imports[key] = nestedImports[key];
@@ -751,6 +957,9 @@ class AleoNetworkClient {
751
957
  catch (error) {
752
958
  logAndThrow("Error fetching program imports: " + error.message);
753
959
  }
960
+ finally {
961
+ this.ctx = {};
962
+ }
754
963
  }
755
964
  /**
756
965
  * Get a list of the program names that a program imports.
@@ -770,12 +979,18 @@ class AleoNetworkClient {
770
979
  */
771
980
  async getProgramImportNames(inputProgram) {
772
981
  try {
773
- const program = inputProgram instanceof Program ? inputProgram : (await this.getProgramObject(inputProgram));
982
+ this.ctx = { "X-ALEO-METHOD": "getProgramImportNames" };
983
+ const program = inputProgram instanceof Program
984
+ ? inputProgram
985
+ : await this.getProgramObject(inputProgram);
774
986
  return program.getImports();
775
987
  }
776
988
  catch (error) {
777
989
  throw new Error(`Error fetching imports for program ${inputProgram instanceof Program ? inputProgram.id() : inputProgram}: ${error.message}`);
778
990
  }
991
+ finally {
992
+ this.ctx = {};
993
+ }
779
994
  }
780
995
  /**
781
996
  * Returns the names of the mappings of a program.
@@ -803,11 +1018,15 @@ class AleoNetworkClient {
803
1018
  */
804
1019
  async getProgramMappingNames(programId) {
805
1020
  try {
1021
+ this.ctx = { "X-ALEO-METHOD": "getProgramMappingNames" };
806
1022
  return await this.fetchData(`/program/${programId}/mappings`);
807
1023
  }
808
1024
  catch (error) {
809
1025
  throw new Error(`Error fetching mappings for program ${programId} - ensure the program exists on chain before trying again`);
810
1026
  }
1027
+ finally {
1028
+ this.ctx = {};
1029
+ }
811
1030
  }
812
1031
  /**
813
1032
  * Returns the value of a program's mapping for a specific key.
@@ -830,12 +1049,16 @@ class AleoNetworkClient {
830
1049
  */
831
1050
  async getProgramMappingValue(programId, mappingName, key) {
832
1051
  try {
1052
+ this.ctx = { "X-ALEO-METHOD": "getProgramMappingValue" };
833
1053
  const keyString = key instanceof Plaintext ? key.toString() : key;
834
1054
  return await this.fetchData(`/program/${programId}/mapping/${mappingName}/${keyString}`);
835
1055
  }
836
1056
  catch (error) {
837
1057
  throw new Error(`Error fetching value for key '${key}' in mapping '${mappingName}' in program '${programId}' - ensure the mapping exists and the key is correct`);
838
1058
  }
1059
+ finally {
1060
+ this.ctx = {};
1061
+ }
839
1062
  }
840
1063
  /**
841
1064
  * Returns the value of a mapping as a wasm Plaintext object. Returning an object in this format allows it to be converted to a Js type and for its internal members to be inspected if it's a struct or array.
@@ -873,6 +1096,7 @@ class AleoNetworkClient {
873
1096
  */
874
1097
  async getProgramMappingPlaintext(programId, mappingName, key) {
875
1098
  try {
1099
+ this.ctx = { "X-ALEO-METHOD": "getProgramMappingPlaintext" };
876
1100
  const keyString = key instanceof Plaintext ? key.toString() : key;
877
1101
  const value = await this.fetchRaw(`/program/${programId}/mapping/${mappingName}/${keyString}`);
878
1102
  return Plaintext.fromString(JSON.parse(value));
@@ -880,6 +1104,9 @@ class AleoNetworkClient {
880
1104
  catch (error) {
881
1105
  throw new Error("Failed to fetch mapping value." + error);
882
1106
  }
1107
+ finally {
1108
+ this.ctx = {};
1109
+ }
883
1110
  }
884
1111
  /**
885
1112
  * Returns the public balance of an address from the account mapping in credits.aleo
@@ -901,13 +1128,17 @@ class AleoNetworkClient {
901
1128
  */
902
1129
  async getPublicBalance(address) {
903
1130
  try {
1131
+ this.ctx = { "X-ALEO-METHOD": "getPublicBalance" };
904
1132
  const addressString = address instanceof Address ? address.to_string() : address;
905
- const balanceStr = await this.getProgramMappingValue('credits.aleo', 'account', addressString);
1133
+ const balanceStr = await this.getProgramMappingValue("credits.aleo", "account", addressString);
906
1134
  return balanceStr ? parseInt(balanceStr) : 0;
907
1135
  }
908
1136
  catch (error) {
909
1137
  throw new Error(`Error fetching public balance for ${address}: ${error}`);
910
1138
  }
1139
+ finally {
1140
+ this.ctx = {};
1141
+ }
911
1142
  }
912
1143
  /**
913
1144
  * Returns the latest state/merkle root of the Aleo blockchain.
@@ -925,11 +1156,15 @@ class AleoNetworkClient {
925
1156
  */
926
1157
  async getStateRoot() {
927
1158
  try {
928
- return await this.fetchData('/stateRoot/latest');
1159
+ this.ctx = { "X-ALEO-METHOD": "getStateRoot" };
1160
+ return await this.fetchData("/stateRoot/latest");
929
1161
  }
930
1162
  catch (error) {
931
1163
  throw new Error(`Error fetching latest state root: ${error}`);
932
1164
  }
1165
+ finally {
1166
+ this.ctx = {};
1167
+ }
933
1168
  }
934
1169
  /**
935
1170
  * Returns a transaction by its unique identifier.
@@ -947,11 +1182,15 @@ class AleoNetworkClient {
947
1182
  */
948
1183
  async getTransaction(transactionId) {
949
1184
  try {
1185
+ this.ctx = { "X-ALEO-METHOD": "getTransaction" };
950
1186
  return await this.fetchData("/transaction/" + transactionId);
951
1187
  }
952
1188
  catch (error) {
953
1189
  throw new Error(`Error fetching transaction ${transactionId}: ${error}`);
954
1190
  }
1191
+ finally {
1192
+ this.ctx = {};
1193
+ }
955
1194
  }
956
1195
  /**
957
1196
  * Returns a confirmed transaction by its unique identifier.
@@ -970,11 +1209,15 @@ class AleoNetworkClient {
970
1209
  */
971
1210
  async getConfirmedTransaction(transactionId) {
972
1211
  try {
1212
+ this.ctx = { "X-ALEO-METHOD": "getConfirmedTransaction" };
973
1213
  return await this.fetchData(`/transaction/confirmed/${transactionId}`);
974
1214
  }
975
1215
  catch (error) {
976
1216
  throw new Error(`Error fetching confirmed transaction ${transactionId}: ${error}`);
977
1217
  }
1218
+ finally {
1219
+ this.ctx = {};
1220
+ }
978
1221
  }
979
1222
  /**
980
1223
  * Returns a transaction as a wasm object. Getting a transaction of this type will allow the ability for the inputs,
@@ -1003,12 +1246,16 @@ class AleoNetworkClient {
1003
1246
  */
1004
1247
  async getTransactionObject(transactionId) {
1005
1248
  try {
1249
+ this.ctx = { "X-ALEO-METHOD": "getTransactionObject" };
1006
1250
  const transaction = await this.fetchRaw("/transaction/" + transactionId);
1007
1251
  return Transaction.fromString(transaction);
1008
1252
  }
1009
1253
  catch (error) {
1010
1254
  throw new Error(`Error fetching transaction object ${transactionId}: ${error}`);
1011
1255
  }
1256
+ finally {
1257
+ this.ctx = {};
1258
+ }
1012
1259
  }
1013
1260
  /**
1014
1261
  * Returns the transactions present at the specified block height.
@@ -1026,11 +1273,15 @@ class AleoNetworkClient {
1026
1273
  */
1027
1274
  async getTransactions(blockHeight) {
1028
1275
  try {
1276
+ this.ctx = { "X-ALEO-METHOD": "getTransactions" };
1029
1277
  return await this.fetchData("/block/" + blockHeight.toString() + "/transactions");
1030
1278
  }
1031
1279
  catch (error) {
1032
1280
  throw new Error(`Error fetching transactions: ${error}`);
1033
1281
  }
1282
+ finally {
1283
+ this.ctx = {};
1284
+ }
1034
1285
  }
1035
1286
  /**
1036
1287
  * Returns the confirmed transactions present in the block with the specified block hash.
@@ -1048,6 +1299,7 @@ class AleoNetworkClient {
1048
1299
  */
1049
1300
  async getTransactionsByBlockHash(blockHash) {
1050
1301
  try {
1302
+ this.ctx = { "X-ALEO-METHOD": "getTransactionsByBlockHash" };
1051
1303
  const block = await this.fetchData(`/block/${blockHash}`);
1052
1304
  const height = block.header.metadata.height;
1053
1305
  return await this.getTransactions(Number(height));
@@ -1055,6 +1307,9 @@ class AleoNetworkClient {
1055
1307
  catch (error) {
1056
1308
  throw new Error(`Error fetching transactions for block ${blockHash}: ${error}`);
1057
1309
  }
1310
+ finally {
1311
+ this.ctx = {};
1312
+ }
1058
1313
  }
1059
1314
  /**
1060
1315
  * Returns the transactions in the memory pool. This method requires access to a validator's REST API.
@@ -1072,11 +1327,15 @@ class AleoNetworkClient {
1072
1327
  */
1073
1328
  async getTransactionsInMempool() {
1074
1329
  try {
1330
+ this.ctx = { "X-ALEO-METHOD": "getTransactionsInMempool" };
1075
1331
  return await this.fetchData("/memoryPool/transactions");
1076
1332
  }
1077
1333
  catch (error) {
1078
1334
  throw new Error(`Error fetching transactions from mempool: ${error}`);
1079
1335
  }
1336
+ finally {
1337
+ this.ctx = {};
1338
+ }
1080
1339
  }
1081
1340
  /**
1082
1341
  * Returns the transition ID of the transition corresponding to the ID of the input or output.
@@ -1088,11 +1347,15 @@ class AleoNetworkClient {
1088
1347
  */
1089
1348
  async getTransitionId(inputOrOutputID) {
1090
1349
  try {
1350
+ this.ctx = { "X-ALEO-METHOD": "getTransitionId" };
1091
1351
  return await this.fetchData("/find/transitionID/" + inputOrOutputID);
1092
1352
  }
1093
1353
  catch (error) {
1094
1354
  throw new Error(`Error fetching transition ID for input/output ${inputOrOutputID}: ${error}`);
1095
1355
  }
1356
+ finally {
1357
+ this.ctx = {};
1358
+ }
1096
1359
  }
1097
1360
  /**
1098
1361
  * Submit an execute or deployment transaction to the Aleo network.
@@ -1101,14 +1364,16 @@ class AleoNetworkClient {
1101
1364
  * @returns {Promise<string>} - The transaction id of the submitted transaction or the resulting error
1102
1365
  */
1103
1366
  async submitTransaction(transaction) {
1104
- const transaction_string = transaction instanceof Transaction ? transaction.toString() : transaction;
1367
+ const transactionString = transaction instanceof Transaction
1368
+ ? transaction.toString()
1369
+ : transaction;
1105
1370
  try {
1106
- const response = await post(this.host + "/transaction/broadcast", {
1107
- body: transaction_string,
1108
- headers: Object.assign({}, this.headers, {
1371
+ const response = await retryWithBackoff(() => this._sendPost(this.host + "/transaction/broadcast", {
1372
+ body: transactionString,
1373
+ headers: Object.assign({}, { ...this.headers, "X-ALEO-METHOD": "submitTransaction" }, {
1109
1374
  "Content-Type": "application/json",
1110
1375
  }),
1111
- });
1376
+ }));
1112
1377
  try {
1113
1378
  const text = await response.text();
1114
1379
  return parseJSON(text);
@@ -1129,22 +1394,22 @@ class AleoNetworkClient {
1129
1394
  */
1130
1395
  async submitSolution(solution) {
1131
1396
  try {
1132
- const response = await post(this.host + "/solution/broadcast", {
1397
+ const response = await retryWithBackoff(() => post(this.host + "/solution/broadcast", {
1133
1398
  body: solution,
1134
- headers: Object.assign({}, this.headers, {
1399
+ headers: Object.assign({}, { ...this.headers, "X-ALEO-METHOD": "submitSolution" }, {
1135
1400
  "Content-Type": "application/json",
1136
1401
  }),
1137
- });
1402
+ }));
1138
1403
  try {
1139
1404
  const text = await response.text();
1140
1405
  return parseJSON(text);
1141
1406
  }
1142
1407
  catch (error) {
1143
- throw new Error(`Error posting transaction. Aleo network response: ${error.message}`);
1408
+ throw new Error(`Error posting solution. Aleo network response: ${error.message}`);
1144
1409
  }
1145
1410
  }
1146
1411
  catch (error) {
1147
- throw new Error(`Error posting transaction: No response received: ${error.message}`);
1412
+ throw new Error(`Error posting solution: No response received: ${error.message}`);
1148
1413
  }
1149
1414
  }
1150
1415
  /**
@@ -1174,23 +1439,55 @@ class AleoNetworkClient {
1174
1439
  * // Wait for the transaction to be confirmed.
1175
1440
  * const transaction = await networkClient.waitForTransactionConfirmation(transactionId);
1176
1441
  */
1177
- async waitForTransactionConfirmation(transactionId, checkInterval = 2000, // Poll every 2 seconds
1178
- timeout = 45000 // Timeout after 45 seconds
1179
- ) {
1442
+ async waitForTransactionConfirmation(transactionId, checkInterval = 2000, timeout = 45000) {
1180
1443
  const startTime = Date.now();
1181
1444
  return new Promise((resolve, reject) => {
1182
1445
  const interval = setInterval(async () => {
1446
+ const elapsed = Date.now() - startTime;
1447
+ if (elapsed > timeout) {
1448
+ clearInterval(interval);
1449
+ return reject(new Error(`Transaction ${transactionId} did not appear after the timeout period of ${interval}ms - consider resubmitting the transaction`));
1450
+ }
1183
1451
  try {
1184
- // Replace with actual Aleo transaction lookup API
1185
- const transaction = await this.getTransactionObject(transactionId);
1186
- resolve(transaction);
1187
- if (Date.now() - startTime > timeout) {
1452
+ const res = await fetch(`${this.host}/transaction/confirmed/${transactionId}`, {
1453
+ headers: {
1454
+ ...this.headers,
1455
+ "X-ALEO-METHOD": "waitForTransactionConfirmation",
1456
+ },
1457
+ });
1458
+ if (!res.ok) {
1459
+ let text = "";
1460
+ try {
1461
+ text = await res.text();
1462
+ console.warn("Response text from server:", text);
1463
+ }
1464
+ catch (err) {
1465
+ console.warn("Failed to read response text:", err);
1466
+ }
1467
+ // If the transaction ID is malformed (e.g. invalid checksum, wrong length),
1468
+ // the API returns a 4XX with "Invalid URL" — we treat this as a fatal error and stop polling.
1469
+ if (res.status >= 400 &&
1470
+ res.status < 500 &&
1471
+ text.includes("Invalid URL")) {
1472
+ clearInterval(interval);
1473
+ return reject(new Error(`Malformed transaction ID: ${text}`));
1474
+ }
1475
+ // Log and continue polling for 404s or 5XX errors in case a tx doesn't exist yet
1476
+ console.warn("Non-OK response (retrying):", res.status, text);
1477
+ return;
1478
+ }
1479
+ const data = parseJSON(await res.text());
1480
+ if (data?.status === "accepted") {
1188
1481
  clearInterval(interval);
1189
- reject(new Error("Transaction confirmation timed out"));
1482
+ return resolve(data);
1483
+ }
1484
+ if (data?.status === "rejected") {
1485
+ clearInterval(interval);
1486
+ return reject(new Error(`Transaction ${transactionId} was rejected by the network. Ensure that the account paying the fee has enough credits and that the inputs to the on-chain function are valid.`));
1190
1487
  }
1191
1488
  }
1192
- catch (error) {
1193
- console.error("Error checking transaction:", error);
1489
+ catch (err) {
1490
+ console.error("Polling error:", err);
1194
1491
  }
1195
1492
  }, checkInterval);
1196
1493
  });
@@ -1709,9 +2006,9 @@ class ProgramManager {
1709
2006
  * @param { FunctionKeyProvider | undefined } keyProvider A key provider that implements {@link FunctionKeyProvider} interface
1710
2007
  * @param { RecordProvider | undefined } recordProvider A record provider that implements {@link RecordProvider} interface
1711
2008
  */
1712
- constructor(host, keyProvider, recordProvider) {
2009
+ constructor(host, keyProvider, recordProvider, networkClientOptions) {
1713
2010
  this.host = host ? host : "https://api.explorer.provable.com/v1";
1714
- this.networkClient = new AleoNetworkClient(this.host);
2011
+ this.networkClient = new AleoNetworkClient(this.host, networkClientOptions);
1715
2012
  this.keyProvider = keyProvider ? keyProvider : new AleoKeyProvider();
1716
2013
  this.recordProvider = recordProvider;
1717
2014
  }
@@ -1757,6 +2054,41 @@ class ProgramManager {
1757
2054
  setRecordProvider(recordProvider) {
1758
2055
  this.recordProvider = recordProvider;
1759
2056
  }
2057
+ /**
2058
+ * Set a header in the `AleoNetworkClient`s header map
2059
+ *
2060
+ * @param {string} headerName The name of the header to set
2061
+ * @param {string} value The header value
2062
+ *
2063
+ * @example
2064
+ * import { ProgramManager } from "@provablehq/sdk/mainnet.js";
2065
+ *
2066
+ * // Create a ProgramManager
2067
+ * const programManager = new ProgramManager("https://api.explorer.provable.com/v1");
2068
+ *
2069
+ * // Set the value of the `Accept-Language` header to `en-US`
2070
+ * programManager.setHeader('Accept-Language', 'en-US');
2071
+ */
2072
+ setHeader(headerName, value) {
2073
+ this.networkClient.headers[headerName] = value;
2074
+ }
2075
+ /**
2076
+ * Remove a header from the `AleoNetworkClient`s header map
2077
+ *
2078
+ * @param {string} headerName The name of the header to be removed
2079
+ *
2080
+ * @example
2081
+ * import { ProgramManager } from "@provablehq/sdk/mainnet.js";
2082
+ *
2083
+ * // Create a ProgramManager
2084
+ * const programManager = new ProgramManager("https://api.explorer.provable.com/v1");
2085
+ *
2086
+ * // Remove the default `X-Aleo-SDK-Version` header
2087
+ * programManager.removeHeader('X-Aleo-SDK-Version');
2088
+ */
2089
+ removeHeader(headerName) {
2090
+ delete this.networkClient.headers[headerName];
2091
+ }
1760
2092
  /**
1761
2093
  * Builds a deployment transaction for submission to the Aleo network.
1762
2094
  *
@@ -3018,18 +3350,44 @@ class ProgramManager {
3018
3350
  return this.networkClient.submitTransaction(tx);
3019
3351
  }
3020
3352
  /**
3021
- * Verify a proof of execution from an offline execution
3353
+ * Verify a proof from an offline execution. This is useful when it is desired to do offchain proving and verification.
3022
3354
  *
3023
- * @param {executionResponse} executionResponse
3355
+ * @param {executionResponse} executionResponse The response from an offline function execution (via the `programManager.run` method)
3356
+ * @param {ImportedPrograms} imports The imported programs used in the execution. Specified as { "programName": "programSourceCode", ... }
3357
+ * @param {ImportedVerifyingKeys} importedVerifyingKeys The verifying keys in the execution. Specified as { "programName": [["functionName", "verifyingKey"], ...], ... }
3024
3358
  * @returns {boolean} True if the proof is valid, false otherwise
3359
+ *
3360
+ * @example
3361
+ * /// Import the mainnet version of the sdk used to build executions.
3362
+ * import { Account, ProgramManager } from "@provablehq/sdk/mainnet.js";
3363
+ *
3364
+ * /// Create the source for two programs.
3365
+ * const program = "import add_it_up.aleo; \n\n program mul_add.aleo;\n\nfunction mul_and_add:\n input r0 as u32.public;\n input r1 as u32.private;\n mul r0 r1 into r2;\n call add_it_up.aleo/add_it r1 r2 into r3; output r3 as u32.private;\n";
3366
+ * const program_import = "program add_it_up.aleo;\n\nfunction add_it:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n";
3367
+ * const programManager = new ProgramManager(undefined, undefined, undefined);
3368
+ *
3369
+ * /// Create a temporary account for the execution of the program
3370
+ * const account = Account.fromCipherText(process.env.ciphertext, process.env.password);
3371
+ * programManager.setAccount(account);
3372
+ *
3373
+ * /// Get the response and ensure that the program executed correctly
3374
+ * const executionResponse = await programManager.run(program, "mul_and_add", ["5u32", "5u32"], true);
3375
+ *
3376
+ * /// Construct the imports and verifying keys
3377
+ * const imports = { "add_it_up.aleo": program_import };
3378
+ * const importedVerifyingKeys = { "add_it_up.aleo": [["add_it", "verifyingKey1..."]] };
3379
+ *
3380
+ * /// Verify the execution.
3381
+ * const isValid = programManager.verifyExecution(executionResponse, imports, importedVerifyingKeys);
3382
+ * assert(isValid);
3025
3383
  */
3026
- verifyExecution(executionResponse) {
3384
+ verifyExecution(executionResponse, imports, importedVerifyingKeys) {
3027
3385
  try {
3028
3386
  const execution = (executionResponse.getExecution());
3029
3387
  const function_id = executionResponse.getFunctionId();
3030
3388
  const program = executionResponse.getProgram();
3031
3389
  const verifyingKey = executionResponse.getVerifyingKey();
3032
- return verifyFunctionExecution(execution, verifyingKey, program, function_id);
3390
+ return verifyFunctionExecution(execution, verifyingKey, program, function_id, imports, importedVerifyingKeys);
3033
3391
  }
3034
3392
  catch (e) {
3035
3393
  console.warn("The execution was not found in the response, cannot verify the execution");
@@ -3097,4 +3455,4 @@ function validateTransferType(transferType) {
3097
3455
  }
3098
3456
 
3099
3457
  export { AleoKeyProvider as A, CREDITS_PROGRAM_KEYS as C, KEY_STORE as K, ProgramManager as P, VALID_TRANSFER_TYPES as V, AleoKeyProviderParams as a, AleoNetworkClient as b, PRIVATE_TRANSFER as c, PRIVATE_TO_PUBLIC_TRANSFER as d, PRIVATE_TRANSFER_TYPES as e, PUBLIC_TRANSFER as f, PUBLIC_TRANSFER_AS_SIGNER as g, PUBLIC_TO_PRIVATE_TRANSFER as h, logAndThrow as l };
3100
- //# sourceMappingURL=program-manager-BuK9g9xJ.js.map
3458
+ //# sourceMappingURL=program-manager-BTHjM8b7.js.map