@provablehq/sdk 0.9.14 → 0.9.15-enc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mainnet/account.d.ts +15 -0
- package/dist/mainnet/browser.d.ts +5 -2
- package/dist/mainnet/browser.js +429 -30
- package/dist/mainnet/browser.js.map +1 -1
- package/dist/mainnet/models/cryptoBoxPubkey.d.ts +4 -0
- package/dist/mainnet/models/encryptedProvingRequest.d.ts +4 -0
- package/dist/mainnet/models/provingResponse.d.ts +48 -2
- package/dist/mainnet/models/record-scanner/encryptedRegistrationRequest.d.ts +8 -0
- package/dist/mainnet/models/record-scanner/registrationResult.d.ts +26 -0
- package/dist/mainnet/network-client.d.ts +48 -2
- package/dist/mainnet/node-polyfill.js +2 -49
- package/dist/mainnet/node-polyfill.js.map +1 -1
- package/dist/mainnet/node.js +2 -2
- package/dist/mainnet/record-scanner.d.ts +53 -5
- package/dist/mainnet/security.d.ts +38 -0
- package/dist/testnet/account.d.ts +15 -0
- package/dist/testnet/browser.d.ts +5 -2
- package/dist/testnet/browser.js +429 -30
- package/dist/testnet/browser.js.map +1 -1
- package/dist/testnet/models/cryptoBoxPubkey.d.ts +4 -0
- package/dist/testnet/models/encryptedProvingRequest.d.ts +4 -0
- package/dist/testnet/models/provingResponse.d.ts +48 -2
- package/dist/testnet/models/record-scanner/encryptedRegistrationRequest.d.ts +8 -0
- package/dist/testnet/models/record-scanner/registrationResult.d.ts +26 -0
- package/dist/testnet/network-client.d.ts +48 -2
- package/dist/testnet/node-polyfill.js +2 -49
- package/dist/testnet/node-polyfill.js.map +1 -1
- package/dist/testnet/node.js +2 -2
- package/dist/testnet/record-scanner.d.ts +53 -5
- package/dist/testnet/security.d.ts +38 -0
- package/package.json +4 -4
|
@@ -52,6 +52,21 @@ export declare class Account {
|
|
|
52
52
|
* const account = Account.fromCiphertext(process.env.ciphertext, process.env.password);
|
|
53
53
|
*/
|
|
54
54
|
static fromCiphertext(ciphertext: PrivateKeyCiphertext | string, password: string): Account;
|
|
55
|
+
/**
|
|
56
|
+
* Validates whether the given input is a valid Aleo address.
|
|
57
|
+
* @param {string | Uint8Array} address The address to validate, either as a string or bytes
|
|
58
|
+
* @returns {boolean} True if the address is valid, false otherwise
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* import { Account } from "@provablehq/sdk/testnet.js";
|
|
62
|
+
*
|
|
63
|
+
* const isValid = Account.isValidAddress("aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px");
|
|
64
|
+
* console.log(isValid); // true
|
|
65
|
+
*
|
|
66
|
+
* const isInvalid = Account.isValidAddress("invalid_address");
|
|
67
|
+
* console.log(isInvalid); // false
|
|
68
|
+
*/
|
|
69
|
+
static isValidAddress(address: string | Uint8Array): boolean;
|
|
55
70
|
/**
|
|
56
71
|
* Creates a PrivateKey from the provided parameters.
|
|
57
72
|
* @param {AccountParam} params The parameters containing either a private key string or a seed
|
|
@@ -3,8 +3,10 @@ import { Account } from "./account.js";
|
|
|
3
3
|
import { AleoNetworkClient, ProgramImports } from "./network-client.js";
|
|
4
4
|
import { BlockJSON, Header, Metadata } from "./models/blockJSON.js";
|
|
5
5
|
import { ConfirmedTransactionJSON } from "./models/confirmed_transaction.js";
|
|
6
|
+
import { CryptoBoxPubKey } from "./models/cryptoBoxPubkey.js";
|
|
6
7
|
import { DeploymentJSON, VerifyingKeys } from "./models/deployment/deploymentJSON.js";
|
|
7
8
|
import { DeploymentObject } from "./models/deployment/deploymentObject.js";
|
|
9
|
+
import { EncryptedProvingRequest } from "./models/encryptedProvingRequest.js";
|
|
8
10
|
import { EncryptedRecord } from "./models/record-provider/encryptedRecord.js";
|
|
9
11
|
import { ExecutionJSON, FeeExecutionJSON } from "./models/execution/executionJSON.js";
|
|
10
12
|
import { ExecutionObject, FeeExecutionObject } from "./models/execution/executionObject.js";
|
|
@@ -24,7 +26,7 @@ import { PlaintextLiteral } from "./models/plaintext/literal.js";
|
|
|
24
26
|
import { PlaintextObject } from "./models/plaintext/plaintext.js";
|
|
25
27
|
import { PlaintextStruct } from "./models/plaintext/struct.js";
|
|
26
28
|
import { ProvingRequestJSON } from "./models/provingRequest.js";
|
|
27
|
-
import { ProvingResponse } from "./models/provingResponse.js";
|
|
29
|
+
import { ProvingResponse, BroadcastResponse, BroadcastResult, ProvingResult, ProvingFailure, ProvingSuccess, ProveApiErrorBody, ProvingRequestError, isProvingResponse, isProveApiErrorBody } from "./models/provingResponse.js";
|
|
28
30
|
import { RatificationJSON } from "./models/ratification.js";
|
|
29
31
|
import { RecordsFilter } from "./models/record-scanner/recordsFilter.js";
|
|
30
32
|
import { RecordsResponseFilter } from "./models/record-scanner/recordsResponseFilter.js";
|
|
@@ -45,4 +47,5 @@ export { logAndThrow } from "./utils.js";
|
|
|
45
47
|
export { Address, Authorization, Boolean, BHP256, BHP512, BHP768, BHP1024, Ciphertext, ComputeKey, Execution as FunctionExecution, ExecutionRequest, ExecutionResponse, EncryptionToolkit, Field, GraphKey, Group, I8, I16, I32, I64, I128, OfflineQuery, Pedersen64, Pedersen128, Plaintext, Poseidon2, Poseidon4, Poseidon8, PrivateKey, PrivateKeyCiphertext, Program, ProgramManager as ProgramManagerBase, ProvingKey, ProvingRequest, RecordCiphertext, RecordPlaintext, Signature, Scalar, Transaction, Transition, U8, U16, U32, U64, U128, VerifyingKey, ViewKey, initThreadPool, getOrInitConsensusVersionTestHeights, verifyFunctionExecution, } from "./wasm.js";
|
|
46
48
|
export { initializeWasm };
|
|
47
49
|
export { Key, CREDITS_PROGRAM_KEYS, KEY_STORE, PRIVATE_TRANSFER, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TRANSFER, PUBLIC_TRANSFER_AS_SIGNER, PUBLIC_TO_PRIVATE_TRANSFER, RECORD_DOMAIN, VALID_TRANSFER_TYPES, } from "./constants.js";
|
|
48
|
-
export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoKeyProviderInitParams, AleoNetworkClient, BlockJSON, BlockHeightSearch, CachedKeyPair, ConfirmedTransactionJSON, DeploymentJSON, DeploymentObject, EncryptedRecord, ExecutionJSON, ExecutionObject, FeeExecutionJSON, FeeExecutionObject, FinalizeJSON, FunctionInput, FunctionObject, FunctionKeyPair, FunctionKeyProvider, Header, ImportedPrograms, ImportedVerifyingKeys, InputJSON, InputObject, KeySearchParams, Metadata, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, OutputJSON, OutputObject, OwnedFilter, OwnedRecord, OwnerJSON, PartialSolutionJSON, PlaintextArray, PlaintextLiteral, PlaintextObject, PlaintextStruct, ProgramImports, ProvingRequestJSON, ProvingResponse, RatificationJSON, RecordsFilter, RecordsResponseFilter, RecordProvider, RecordScanner, RecordSearchParams, SealanceMerkleTree, SolutionJSON, SolutionsJSON, TransactionJSON, TransactionObject, TransitionJSON, TransitionObject, VerifyingKeys, };
|
|
50
|
+
export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoKeyProviderInitParams, AleoNetworkClient, BlockJSON, BlockHeightSearch, BroadcastResponse, BroadcastResult, CachedKeyPair, ConfirmedTransactionJSON, CryptoBoxPubKey, DeploymentJSON, DeploymentObject, EncryptedProvingRequest, EncryptedRecord, ExecutionJSON, ExecutionObject, FeeExecutionJSON, FeeExecutionObject, FinalizeJSON, FunctionInput, FunctionObject, FunctionKeyPair, FunctionKeyProvider, Header, isProvingResponse, isProveApiErrorBody, ImportedPrograms, ImportedVerifyingKeys, InputJSON, InputObject, KeySearchParams, Metadata, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, OutputJSON, OutputObject, OwnedFilter, OwnedRecord, OwnerJSON, PartialSolutionJSON, PlaintextArray, PlaintextLiteral, PlaintextObject, PlaintextStruct, ProgramImports, ProveApiErrorBody, ProvingFailure, ProvingRequestError, ProvingRequestJSON, ProvingResult, ProvingSuccess, ProvingResponse, RatificationJSON, RecordsFilter, RecordsResponseFilter, RecordProvider, RecordScanner, RecordSearchParams, SealanceMerkleTree, SolutionJSON, SolutionsJSON, TransactionJSON, TransactionObject, TransitionJSON, TransitionObject, VerifyingKeys, };
|
|
51
|
+
export { encryptAuthorization, encryptProvingRequest, encryptViewKey, encryptRegistrationRequest } from "./security.js";
|
package/dist/mainnet/browser.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'core-js/proposals/json-parse-with-source.js';
|
|
2
2
|
import { ViewKey, ComputeKey, Address, PrivateKeyCiphertext, PrivateKey, RecordCiphertext, EncryptionToolkit, Group, Metadata, VerifyingKey, Program, Plaintext, Transaction, ProvingRequest, ProvingKey, RecordPlaintext, Field, Poseidon4, ProgramManager as ProgramManager$1, verifyFunctionExecution } from '@provablehq/wasm/mainnet.js';
|
|
3
3
|
export { Address, Authorization, BHP1024, BHP256, BHP512, BHP768, Boolean, Ciphertext, ComputeKey, 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, ProvingKey, ProvingRequest, RecordCiphertext, RecordPlaintext, Scalar, Signature, Transaction, Transition, U128, U16, U32, U64, U8, VerifyingKey, ViewKey, getOrInitConsensusVersionTestHeights, initThreadPool, verifyFunctionExecution } from '@provablehq/wasm/mainnet.js';
|
|
4
|
+
import sodium from 'libsodium-wrappers';
|
|
4
5
|
import { bech32m } from '@scure/base';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -72,6 +73,23 @@ class Account {
|
|
|
72
73
|
throw new Error("Wrong password or invalid ciphertext");
|
|
73
74
|
}
|
|
74
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Validates whether the given input is a valid Aleo address.
|
|
78
|
+
* @param {string | Uint8Array} address The address to validate, either as a string or bytes
|
|
79
|
+
* @returns {boolean} True if the address is valid, false otherwise
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* import { Account } from "@provablehq/sdk/testnet.js";
|
|
83
|
+
*
|
|
84
|
+
* const isValid = Account.isValidAddress("aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px");
|
|
85
|
+
* console.log(isValid); // true
|
|
86
|
+
*
|
|
87
|
+
* const isInvalid = Account.isValidAddress("invalid_address");
|
|
88
|
+
* console.log(isInvalid); // false
|
|
89
|
+
*/
|
|
90
|
+
static isValidAddress(address) {
|
|
91
|
+
return Address.isValid(address);
|
|
92
|
+
}
|
|
75
93
|
/**
|
|
76
94
|
* Creates a PrivateKey from the provided parameters.
|
|
77
95
|
* @param {AccountParam} params The parameters containing either a private key string or a seed
|
|
@@ -466,6 +484,91 @@ async function retryWithBackoff(fn, { maxAttempts = 5, baseDelay = 100, jitter,
|
|
|
466
484
|
throw new Error("retryWithBackoff: unreachable");
|
|
467
485
|
}
|
|
468
486
|
|
|
487
|
+
/** Type guard: value is a ProvingResponse. */
|
|
488
|
+
function isProvingResponse(value) {
|
|
489
|
+
return (typeof value === "object" &&
|
|
490
|
+
value !== null &&
|
|
491
|
+
"transaction" in value &&
|
|
492
|
+
"broadcast_result" in value &&
|
|
493
|
+
typeof value.broadcast_result === "object");
|
|
494
|
+
}
|
|
495
|
+
/** Type guard: value is a ProveApiErrorBody. */
|
|
496
|
+
function isProveApiErrorBody(value) {
|
|
497
|
+
return (typeof value === "object" &&
|
|
498
|
+
value !== null &&
|
|
499
|
+
"message" in value);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
await sodium.ready;
|
|
503
|
+
/**
|
|
504
|
+
* Encrypt an authorization with a libsodium cryptobox public key.
|
|
505
|
+
*
|
|
506
|
+
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
507
|
+
* @param {Authorization} authorization the authorization to encrypt.
|
|
508
|
+
*
|
|
509
|
+
* @returns {string} the encrypted authorization in RFC 4648 standard Base64.
|
|
510
|
+
*/
|
|
511
|
+
function encryptAuthorization(publicKey, authorization) {
|
|
512
|
+
// Ready the cryptobox lib.
|
|
513
|
+
return encryptMessage(publicKey, authorization.toBytesLe());
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Encrypt a ProvingRequest with a libsodium cryptobox public key.
|
|
517
|
+
*
|
|
518
|
+
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
519
|
+
* @param {Authorization} provingRequest the ProvingRequest to encrypt.
|
|
520
|
+
*
|
|
521
|
+
* @returns {string} the encrypted ProvingRequest in RFC 4648 standard Base64.
|
|
522
|
+
*/
|
|
523
|
+
function encryptProvingRequest(publicKey, provingRequest) {
|
|
524
|
+
return encryptMessage(publicKey, provingRequest.toBytesLe());
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Encrypt a view key with a libsodium cryptobox public key.
|
|
528
|
+
*
|
|
529
|
+
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
530
|
+
* @param {ViewKey} viewKey the view key to encrypt.
|
|
531
|
+
*
|
|
532
|
+
* @returns {string} the encrypted view key in RFC 4648 standard Base64.
|
|
533
|
+
*/
|
|
534
|
+
function encryptViewKey(publicKey, viewKey) {
|
|
535
|
+
return encryptMessage(publicKey, viewKey.toBytesLe());
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Encrypt a record scanner registration request.
|
|
539
|
+
*
|
|
540
|
+
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
541
|
+
* @param {ViewKey} viewKey the view key to encrypt.
|
|
542
|
+
* @param {number} start the start height of the registration request.
|
|
543
|
+
*
|
|
544
|
+
* @returns {string} the encrypted view key in RFC 4648 standard Base64.
|
|
545
|
+
*/
|
|
546
|
+
function encryptRegistrationRequest(publicKey, viewKey, start) {
|
|
547
|
+
// Turn the view key into a Uint8Array.
|
|
548
|
+
const vk_bytes = viewKey.toBytesLe();
|
|
549
|
+
// Create a new array to hold the original bytes and the 4-byte start height.
|
|
550
|
+
const bytes = new Uint8Array(vk_bytes.length + 4);
|
|
551
|
+
// Copy existing bytes.
|
|
552
|
+
bytes.set(vk_bytes, 0);
|
|
553
|
+
// Write the 4-byte number in LE format at the end of the array.
|
|
554
|
+
const view = new DataView(bytes.buffer);
|
|
555
|
+
view.setUint32(vk_bytes.length, start, true);
|
|
556
|
+
// Encrypt the encoded bytes.
|
|
557
|
+
return encryptMessage(publicKey, bytes);
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Encrypt arbitrary bytes with a libsodium cryptobox public key.
|
|
561
|
+
*
|
|
562
|
+
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
563
|
+
* @param {Uint8Array} message the bytes to encrypt.
|
|
564
|
+
*
|
|
565
|
+
* @returns {string} the encrypted bytes in RFC 4648 standard Base64.
|
|
566
|
+
*/
|
|
567
|
+
function encryptMessage(publicKey, message) {
|
|
568
|
+
const publicKeyBytes = sodium.from_base64(publicKey, sodium.base64_variants.ORIGINAL);
|
|
569
|
+
return sodium.to_base64(sodium.crypto_box_seal(message, publicKeyBytes), sodium.base64_variants.ORIGINAL);
|
|
570
|
+
}
|
|
571
|
+
|
|
469
572
|
const KEY_STORE = Metadata.baseUrl();
|
|
470
573
|
function convert(metadata) {
|
|
471
574
|
// This looks up the method name in VerifyingKey
|
|
@@ -591,18 +694,37 @@ class AleoNetworkClient {
|
|
|
591
694
|
apiKey;
|
|
592
695
|
consumerId;
|
|
593
696
|
jwtData;
|
|
697
|
+
proverUri;
|
|
698
|
+
recordScannerUri;
|
|
594
699
|
constructor(host, options) {
|
|
595
700
|
this.host = host + "/mainnet";
|
|
596
701
|
this.network = "mainnet";
|
|
597
702
|
this.ctx = {};
|
|
598
703
|
this.verboseErrors = true;
|
|
599
|
-
if (options
|
|
600
|
-
|
|
704
|
+
if (options) {
|
|
705
|
+
if (options.headers) {
|
|
706
|
+
this.headers = options.headers;
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
this.headers = {
|
|
710
|
+
// This is replaced by the actual version by a Rollup plugin
|
|
711
|
+
"X-Aleo-SDK-Version": "0.9.15-enc",
|
|
712
|
+
"X-Aleo-environment": environment(),
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
// If a prover uri was specified, set the prover uri.
|
|
716
|
+
if (options.proverUri) {
|
|
717
|
+
this.proverUri = options.proverUri + "/mainnet";
|
|
718
|
+
}
|
|
719
|
+
// If a record scanner uri was specified, set the record scanner uri.
|
|
720
|
+
if (options.recordScannerUri) {
|
|
721
|
+
this.recordScannerUri = options.recordScannerUri + "/mainnet";
|
|
722
|
+
}
|
|
601
723
|
}
|
|
602
724
|
else {
|
|
603
725
|
this.headers = {
|
|
604
726
|
// This is replaced by the actual version by a Rollup plugin
|
|
605
|
-
"X-Aleo-SDK-Version": "0.9.
|
|
727
|
+
"X-Aleo-SDK-Version": "0.9.15-enc",
|
|
606
728
|
"X-Aleo-environment": environment(),
|
|
607
729
|
};
|
|
608
730
|
}
|
|
@@ -647,6 +769,40 @@ class AleoNetworkClient {
|
|
|
647
769
|
setHost(host) {
|
|
648
770
|
this.host = host + "/mainnet";
|
|
649
771
|
}
|
|
772
|
+
/**
|
|
773
|
+
* Set a new uri for a remote prover.
|
|
774
|
+
*
|
|
775
|
+
* @param {string} proverUri The uri of the remote prover.
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* import { AleoNetworkClient } from "@provablehq/sdk/mainnet.js";
|
|
779
|
+
*
|
|
780
|
+
* // Create a networkClient that connects to the provable explorer api.
|
|
781
|
+
* const networkClient = new AleoNetworkClient("http://api.explorer.provable.com/v1", undefined);
|
|
782
|
+
*
|
|
783
|
+
* // Set the prover uri.
|
|
784
|
+
* networkClient.setProverUri("https://prover.provable.prove");
|
|
785
|
+
*/
|
|
786
|
+
setProverUri(proverUri) {
|
|
787
|
+
this.proverUri = proverUri + "/mainnet";
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Set a new uri for a remote record scanner.
|
|
791
|
+
*
|
|
792
|
+
* @param {string} recordScannerUri The uri of the remote record scanner.
|
|
793
|
+
*
|
|
794
|
+
* @example
|
|
795
|
+
* import { AleoNetworkClient } from "@provablehq/sdk/mainnet.js";
|
|
796
|
+
*
|
|
797
|
+
* // Create a networkClient that connects to the provable explorer api.
|
|
798
|
+
* const networkClient = new AleoNetworkClient("http://api.explorer.provable.com/v1", undefined);
|
|
799
|
+
*
|
|
800
|
+
* // Set the record scanner uri.
|
|
801
|
+
* networkClient.setRecordScannerUri("https://scanner.provable.scan");
|
|
802
|
+
*/
|
|
803
|
+
setRecordScannerUri(recordScannerUri) {
|
|
804
|
+
this.recordScannerUri = recordScannerUri + "/mainnet";
|
|
805
|
+
}
|
|
650
806
|
/**
|
|
651
807
|
* Set verbose errors to true or false for the `AleoNetworkClient`. When set to true, if `submitTransaction` fails, the failure responses will report descriptive information as to why the transaction failed.
|
|
652
808
|
*
|
|
@@ -1972,33 +2128,87 @@ class AleoNetworkClient {
|
|
|
1972
2128
|
};
|
|
1973
2129
|
}
|
|
1974
2130
|
/**
|
|
1975
|
-
*
|
|
2131
|
+
* Parses a /prove or /prove/encrypted response. Returns a result object (never throws for 200/400/500/503).
|
|
2132
|
+
*/
|
|
2133
|
+
async handleProvingResponse(response) {
|
|
2134
|
+
// Get the proving response text.
|
|
2135
|
+
const text = await response.text();
|
|
2136
|
+
let body;
|
|
2137
|
+
// Parse the body.
|
|
2138
|
+
try {
|
|
2139
|
+
body = parseJSON(text);
|
|
2140
|
+
}
|
|
2141
|
+
catch {
|
|
2142
|
+
body = {};
|
|
2143
|
+
}
|
|
2144
|
+
// If the status is 200, attempt to parse the Proving Request along its expected structure.
|
|
2145
|
+
if (response.status === 200) {
|
|
2146
|
+
if (isProvingResponse(body)) {
|
|
2147
|
+
return { ok: true, data: body };
|
|
2148
|
+
}
|
|
2149
|
+
return {
|
|
2150
|
+
ok: false,
|
|
2151
|
+
status: response.status,
|
|
2152
|
+
error: { message: "Invalid response from proving service" },
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
// If the response is non 200, return the information back to the caller so it can be handled.
|
|
2156
|
+
if (response.status === 400 || response.status === 500 || response.status === 503) {
|
|
2157
|
+
const error = isProveApiErrorBody(body)
|
|
2158
|
+
? body
|
|
2159
|
+
: { message: text || `${response.status} error` };
|
|
2160
|
+
return { ok: false, status: response.status, error };
|
|
2161
|
+
}
|
|
2162
|
+
return {
|
|
2163
|
+
ok: false,
|
|
2164
|
+
status: response.status,
|
|
2165
|
+
error: { message: text || `${response.status} error` },
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
/**
|
|
2169
|
+
* Submit a `ProvingRequest` to a remote proving service for delegated proving. If the broadcast flag of the `ProvingRequest` is set to `true` the remote service will attempt to broadcast the result `Transaction` on behalf of the requestor. Throws on HTTP 400, 500, 503 (and retries on 500/503). Callers should {@link submitProvingRequestSafe} to handle proving request failures without throwing.
|
|
1976
2170
|
*
|
|
1977
2171
|
* @param {DelegatedProvingParams} options - The optional parameters required to submit a proving request.
|
|
1978
2172
|
* @returns {Promise<ProvingResponse>} The ProvingResponse containing the transaction result and the result of the broadcast if the `broadcast` flag was set to `true`.
|
|
1979
2173
|
*/
|
|
1980
2174
|
async submitProvingRequest(options) {
|
|
1981
|
-
const
|
|
2175
|
+
const result = await this.submitProvingRequestSafe(options);
|
|
2176
|
+
if (result.ok) {
|
|
2177
|
+
return result.data;
|
|
2178
|
+
}
|
|
2179
|
+
const err = new Error(result.error.message);
|
|
2180
|
+
err.status = result.status;
|
|
2181
|
+
throw err;
|
|
2182
|
+
}
|
|
2183
|
+
/**
|
|
2184
|
+
* Submit a proving request and return a result object instead of throwing. This method is usable when callers want to handle HTTP status (400, 500, 503) yourself. Retries on 500/503 and returns on 200 or 400.
|
|
2185
|
+
*
|
|
2186
|
+
* @param {DelegatedProvingParams} options - The optional parameters required to submit a proving request.
|
|
2187
|
+
* @returns {Promise<ProvingResult>} `{ ok: true, data }` on success (200), or `{ ok: false, status, error }` on 400/500/503. Check `result.ok` and then either `result.data` or `result.status` / `result.error.message`.
|
|
2188
|
+
*/
|
|
2189
|
+
async submitProvingRequestSafe(options) {
|
|
2190
|
+
// Attempt to get the Prover URI first from the options, then from any configured globally, or third try the main configured host.
|
|
2191
|
+
const proverUri = (options.url ?? this.proverUri) ?? this.host;
|
|
1982
2192
|
const provingRequestString = options.provingRequest instanceof ProvingRequest
|
|
1983
2193
|
? options.provingRequest.toString()
|
|
1984
2194
|
: options.provingRequest;
|
|
2195
|
+
// Try to get JWT data to access the Provable API.
|
|
1985
2196
|
const apiKey = options.apiKey ?? this.apiKey;
|
|
1986
2197
|
const consumerId = options.consumerId ?? this.consumerId;
|
|
1987
2198
|
let jwtData = options.jwtData ?? this.jwtData;
|
|
1988
|
-
// Check if JWT
|
|
1989
|
-
const
|
|
1990
|
-
const isExpired = jwtData && Date.now() >= jwtData.expiration - bufferTime;
|
|
2199
|
+
// Check to see if the JWT needs refreshing.
|
|
2200
|
+
const isExpired = jwtData && Date.now() >= jwtData.expiration - FIVE_MINUTES;
|
|
1991
2201
|
if (!jwtData || isExpired) {
|
|
1992
2202
|
if (options.apiKey && options.consumerId) {
|
|
1993
2203
|
jwtData = await this.refreshJwt(apiKey, consumerId);
|
|
1994
|
-
// Update both the class and the options with the new JWT
|
|
1995
2204
|
this.jwtData = jwtData;
|
|
1996
2205
|
options.jwtData = jwtData;
|
|
1997
2206
|
}
|
|
1998
2207
|
else {
|
|
1999
|
-
|
|
2208
|
+
console.warn('JWT or both apiKey and consumerId are required when using the Provable API');
|
|
2000
2209
|
}
|
|
2001
2210
|
}
|
|
2211
|
+
// Create the necessary headers to hit the provable api.
|
|
2002
2212
|
const headers = {
|
|
2003
2213
|
...this.headers,
|
|
2004
2214
|
"X-ALEO-METHOD": "submitProvingRequest",
|
|
@@ -2007,17 +2217,67 @@ class AleoNetworkClient {
|
|
|
2007
2217
|
if (jwtData?.jwt) {
|
|
2008
2218
|
headers["Authorization"] = jwtData.jwt;
|
|
2009
2219
|
}
|
|
2010
|
-
|
|
2011
|
-
|
|
2220
|
+
// Encapsulate the requests in a locally scoped function that can be run with a retry closure.
|
|
2221
|
+
const runRequest = async () => {
|
|
2222
|
+
// If DPS privacy is set, call invoke the encrypted flow.
|
|
2223
|
+
if (options.dpsPrivacy) {
|
|
2224
|
+
// Get an ephemeral public key from a DPS service.
|
|
2225
|
+
const pubKeyResponse = await get(proverUri + "/pubkey", {
|
|
2226
|
+
headers,
|
|
2227
|
+
});
|
|
2228
|
+
// Encrypt the provingRequest.
|
|
2229
|
+
const pubkey = parseJSON(await pubKeyResponse.text());
|
|
2230
|
+
const ciphertext = encryptProvingRequest(pubkey.public_key, ProvingRequest.fromString(provingRequestString));
|
|
2231
|
+
// Form the expected query a DPS service expects (including the key_id).
|
|
2232
|
+
const payload = {
|
|
2233
|
+
key_id: pubkey.key_id,
|
|
2234
|
+
ciphertext: ciphertext,
|
|
2235
|
+
};
|
|
2236
|
+
const res = await fetch(`${proverUri}/prove/encrypted`, {
|
|
2237
|
+
method: "POST",
|
|
2238
|
+
body: JSON.stringify(payload),
|
|
2239
|
+
headers,
|
|
2240
|
+
});
|
|
2241
|
+
// Properly handle the proving response.
|
|
2242
|
+
return this.handleProvingResponse(res);
|
|
2243
|
+
}
|
|
2244
|
+
// If encrypted usage is not specified use the unencrypted endpoint.
|
|
2245
|
+
const proveEndpoint = proverUri.endsWith("/prove")
|
|
2246
|
+
? proverUri
|
|
2247
|
+
: proverUri + "/prove";
|
|
2248
|
+
const res = await fetch(proveEndpoint, {
|
|
2249
|
+
method: "POST",
|
|
2012
2250
|
body: provingRequestString,
|
|
2013
|
-
headers
|
|
2014
|
-
})
|
|
2015
|
-
|
|
2016
|
-
return
|
|
2251
|
+
headers,
|
|
2252
|
+
});
|
|
2253
|
+
// Properly handle the proving response.
|
|
2254
|
+
return this.handleProvingResponse(res);
|
|
2255
|
+
};
|
|
2256
|
+
try {
|
|
2257
|
+
// Run the request with retries.
|
|
2258
|
+
return await retryWithBackoff(async () => {
|
|
2259
|
+
// Run the encrypted or non-encrypted flow as specified by the flags.
|
|
2260
|
+
const result = await runRequest();
|
|
2261
|
+
if (result.ok) {
|
|
2262
|
+
return result;
|
|
2263
|
+
}
|
|
2264
|
+
// If 500s are hit responses are returned, attempt retries.
|
|
2265
|
+
if (result.status === 500 || result.status === 503) {
|
|
2266
|
+
const err = new Error(result.error.message);
|
|
2267
|
+
err.status = result.status;
|
|
2268
|
+
throw err;
|
|
2269
|
+
}
|
|
2270
|
+
return result;
|
|
2271
|
+
});
|
|
2017
2272
|
}
|
|
2018
|
-
catch (
|
|
2019
|
-
|
|
2020
|
-
|
|
2273
|
+
catch (err) {
|
|
2274
|
+
// If an error is returned, provide usable information to the caller.
|
|
2275
|
+
const e = err;
|
|
2276
|
+
return {
|
|
2277
|
+
ok: false,
|
|
2278
|
+
status: e.status ?? 500,
|
|
2279
|
+
error: { message: e.message },
|
|
2280
|
+
};
|
|
2021
2281
|
}
|
|
2022
2282
|
}
|
|
2023
2283
|
/**
|
|
@@ -3333,6 +3593,20 @@ class BlockHeightSearch {
|
|
|
3333
3593
|
}
|
|
3334
3594
|
}
|
|
3335
3595
|
|
|
3596
|
+
/**
|
|
3597
|
+
* Error thrown when a record scanner request fails (e.g. /register, /register/encrypted).
|
|
3598
|
+
* Includes HTTP status so callers can handle 422 vs 500 etc.
|
|
3599
|
+
*/
|
|
3600
|
+
class RecordScannerRequestError extends Error {
|
|
3601
|
+
status;
|
|
3602
|
+
constructor(message, status) {
|
|
3603
|
+
super(message);
|
|
3604
|
+
this.name = "RecordScannerRequestError";
|
|
3605
|
+
this.status = status;
|
|
3606
|
+
Object.setPrototypeOf(this, RecordScannerRequestError.prototype);
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3336
3610
|
/**
|
|
3337
3611
|
* RecordScanner is a RecordProvider implementation that uses the record scanner service to find records.
|
|
3338
3612
|
*
|
|
@@ -3342,7 +3616,8 @@ class BlockHeightSearch {
|
|
|
3342
3616
|
* const recordScanner = new RecordScanner({ url: "https://record-scanner.aleo.org" });
|
|
3343
3617
|
* recordScanner.setAccount(account);
|
|
3344
3618
|
* recordScanner.setApiKey("your-api-key");
|
|
3345
|
-
* const
|
|
3619
|
+
* const result = await recordScanner.register(viewKey, 0);
|
|
3620
|
+
* if (result.ok) { const uuid = result.data.uuid; }
|
|
3346
3621
|
*
|
|
3347
3622
|
* const filter = {
|
|
3348
3623
|
* uuid,
|
|
@@ -3378,9 +3653,21 @@ class RecordScanner {
|
|
|
3378
3653
|
url;
|
|
3379
3654
|
apiKey;
|
|
3380
3655
|
uuid;
|
|
3656
|
+
consumerId;
|
|
3657
|
+
jwtData;
|
|
3381
3658
|
constructor(options) {
|
|
3382
|
-
|
|
3659
|
+
// Set the network by detecting which version of the SDK is being used.
|
|
3660
|
+
const network = "/mainnet";
|
|
3661
|
+
// If the user has configured a network in their uri, throw
|
|
3662
|
+
if (options.url.endsWith("/mainnet") || options.url.endsWith("/testnet")) {
|
|
3663
|
+
throw new Error("The record scanning url should not include the specific network, this is automatically configured by the Provable SDK.");
|
|
3664
|
+
}
|
|
3665
|
+
// Configure the url to use the network the SDK is using.
|
|
3666
|
+
this.url = options.url + network;
|
|
3667
|
+
// Configure authentication options/
|
|
3383
3668
|
this.apiKey = typeof options.apiKey === "string" ? { header: "X-Provable-API-Key", value: options.apiKey } : options.apiKey;
|
|
3669
|
+
this.consumerId = options.consumerId;
|
|
3670
|
+
this.jwtData = options.jwtData;
|
|
3384
3671
|
}
|
|
3385
3672
|
/**
|
|
3386
3673
|
* Set the API key to use for the record scanner.
|
|
@@ -3390,6 +3677,59 @@ class RecordScanner {
|
|
|
3390
3677
|
async setApiKey(apiKey) {
|
|
3391
3678
|
this.apiKey = typeof apiKey === "string" ? { header: "X-Provable-API-Key", value: apiKey } : apiKey;
|
|
3392
3679
|
}
|
|
3680
|
+
/**
|
|
3681
|
+
* Set the consumer ID used for JWT refresh when using authenticated record scanner (e.g. Provable API).
|
|
3682
|
+
*/
|
|
3683
|
+
async setConsumerId(consumerId) {
|
|
3684
|
+
this.consumerId = consumerId;
|
|
3685
|
+
}
|
|
3686
|
+
/**
|
|
3687
|
+
* Set JWT data for authentication. Optional; when not set, JWT can be refreshed from apiKey + consumerId if provided.
|
|
3688
|
+
*/
|
|
3689
|
+
async setJwtData(jwtData) {
|
|
3690
|
+
this.jwtData = jwtData;
|
|
3691
|
+
}
|
|
3692
|
+
/**
|
|
3693
|
+
* Refreshes the JWT by making a POST request to /jwts/{consumer_id}. Used when authentication is required.
|
|
3694
|
+
*/
|
|
3695
|
+
async refreshJwt(apiKey, consumerId) {
|
|
3696
|
+
const response = await post(`https://api.provable.com/jwts/${consumerId}`, {
|
|
3697
|
+
headers: {
|
|
3698
|
+
"X-Provable-API-Key": apiKey,
|
|
3699
|
+
},
|
|
3700
|
+
});
|
|
3701
|
+
const authHeader = response.headers.get("authorization");
|
|
3702
|
+
if (!authHeader) {
|
|
3703
|
+
throw new Error("No authorization header in JWT refresh response");
|
|
3704
|
+
}
|
|
3705
|
+
const body = await response.json();
|
|
3706
|
+
return {
|
|
3707
|
+
jwt: authHeader,
|
|
3708
|
+
expiration: body.exp * 1000, // Convert to milliseconds
|
|
3709
|
+
};
|
|
3710
|
+
}
|
|
3711
|
+
/**
|
|
3712
|
+
* Returns auth headers (e.g. Authorization with JWT). Refreshes JWT if expired and apiKey + consumerId are set. Empty when auth is not configured.
|
|
3713
|
+
*/
|
|
3714
|
+
async getAuthHeaders() {
|
|
3715
|
+
let jwtData = this.jwtData;
|
|
3716
|
+
const isExpired = jwtData && Date.now() >= jwtData.expiration - FIVE_MINUTES;
|
|
3717
|
+
if (!jwtData || isExpired) {
|
|
3718
|
+
const apiKey = this.apiKey?.value;
|
|
3719
|
+
if (apiKey && this.consumerId) {
|
|
3720
|
+
jwtData = await this.refreshJwt(apiKey, this.consumerId);
|
|
3721
|
+
this.jwtData = jwtData;
|
|
3722
|
+
}
|
|
3723
|
+
else if (jwtData?.jwt) {
|
|
3724
|
+
// Use existing JWT even if expired when we can't refresh
|
|
3725
|
+
return { Authorization: jwtData.jwt };
|
|
3726
|
+
}
|
|
3727
|
+
else {
|
|
3728
|
+
return {};
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
return jwtData?.jwt ? { Authorization: jwtData.jwt } : {};
|
|
3732
|
+
}
|
|
3393
3733
|
/**
|
|
3394
3734
|
* Set the UUID to use for the record scanner.
|
|
3395
3735
|
*
|
|
@@ -3399,14 +3739,15 @@ class RecordScanner {
|
|
|
3399
3739
|
this.uuid = uuidOrViewKey instanceof ViewKey ? this.computeUUID(uuidOrViewKey) : uuidOrViewKey;
|
|
3400
3740
|
}
|
|
3401
3741
|
/**
|
|
3402
|
-
* Register the account with the record scanner service.
|
|
3742
|
+
* Register the account with the record scanner service (unencrypted POST /register). Does not throw if a valid error response from the record scanner is received; returns a result object instead.
|
|
3403
3743
|
*
|
|
3744
|
+
* @param {ViewKey} viewKey The view key to register.
|
|
3404
3745
|
* @param {number} startBlock The block height to start scanning from.
|
|
3405
|
-
* @returns {Promise<
|
|
3746
|
+
* @returns {Promise<RegisterResult>} `{ ok: true, data }` on success, or `{ ok: false, status, error }` on failure.
|
|
3406
3747
|
*/
|
|
3407
3748
|
async register(viewKey, startBlock) {
|
|
3408
3749
|
try {
|
|
3409
|
-
|
|
3750
|
+
const request = {
|
|
3410
3751
|
view_key: viewKey.to_string(),
|
|
3411
3752
|
start: startBlock,
|
|
3412
3753
|
};
|
|
@@ -3417,11 +3758,63 @@ class RecordScanner {
|
|
|
3417
3758
|
}));
|
|
3418
3759
|
const data = await response.json();
|
|
3419
3760
|
this.uuid = data.uuid;
|
|
3420
|
-
return data;
|
|
3761
|
+
return { ok: true, data };
|
|
3421
3762
|
}
|
|
3422
|
-
catch (
|
|
3423
|
-
|
|
3424
|
-
|
|
3763
|
+
catch (err) {
|
|
3764
|
+
if (err instanceof RecordScannerRequestError) {
|
|
3765
|
+
return {
|
|
3766
|
+
ok: false,
|
|
3767
|
+
status: err.status,
|
|
3768
|
+
error: { message: err.message },
|
|
3769
|
+
};
|
|
3770
|
+
}
|
|
3771
|
+
console.error(`Failed to register view key: ${err}`);
|
|
3772
|
+
throw err;
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
/**
|
|
3776
|
+
* Fetches an ephemeral public key from the record scanner service for use with registerEncrypted.
|
|
3777
|
+
* Follows the same pattern as the delegated proving service /pubkey endpoint.
|
|
3778
|
+
*
|
|
3779
|
+
* @returns {Promise<CryptoBoxPubKey>} The service's ephemeral public key and key_id.
|
|
3780
|
+
*/
|
|
3781
|
+
async getPubkey() {
|
|
3782
|
+
const response = await this.request(new Request(`${this.url}/pubkey`, { method: "GET" }));
|
|
3783
|
+
return parseJSON(await response.text());
|
|
3784
|
+
}
|
|
3785
|
+
/**
|
|
3786
|
+
* Registers the account with the record scanner service using the encrypted flow: 1. fetches an ephemeral public key from /pubkey - 2. encrypts the registration request (view key + start block) - 3. POSTs to /register/encrypted. Does not HTTP error on a proper error response from the record scanner; returns a result object instead.
|
|
3787
|
+
*
|
|
3788
|
+
* @param {ViewKey} viewKey The view key to register.
|
|
3789
|
+
* @param {number} startBlock The block height to start scanning from.
|
|
3790
|
+
* @returns {Promise<RegisterResult>} `{ ok: true, data }` on success, or `{ ok: false, status, error }` on failure.
|
|
3791
|
+
*/
|
|
3792
|
+
async registerEncrypted(viewKey, startBlock) {
|
|
3793
|
+
try {
|
|
3794
|
+
const pubkey = await this.getPubkey();
|
|
3795
|
+
const ciphertext = encryptRegistrationRequest(pubkey.public_key, viewKey, startBlock);
|
|
3796
|
+
const payload = {
|
|
3797
|
+
key_id: pubkey.key_id,
|
|
3798
|
+
ciphertext,
|
|
3799
|
+
};
|
|
3800
|
+
const response = await this.request(new Request(`${this.url}/register/encrypted`, {
|
|
3801
|
+
method: "POST",
|
|
3802
|
+
headers: { "Content-Type": "application/json" },
|
|
3803
|
+
body: JSON.stringify(payload),
|
|
3804
|
+
}));
|
|
3805
|
+
const data = await response.json();
|
|
3806
|
+
this.uuid = data.uuid;
|
|
3807
|
+
return { ok: true, data };
|
|
3808
|
+
}
|
|
3809
|
+
catch (err) {
|
|
3810
|
+
if (err instanceof RecordScannerRequestError) {
|
|
3811
|
+
return {
|
|
3812
|
+
ok: false,
|
|
3813
|
+
status: err.status,
|
|
3814
|
+
error: { message: err.message },
|
|
3815
|
+
};
|
|
3816
|
+
}
|
|
3817
|
+
throw err;
|
|
3425
3818
|
}
|
|
3426
3819
|
}
|
|
3427
3820
|
/**
|
|
@@ -3614,18 +4007,24 @@ class RecordScanner {
|
|
|
3614
4007
|
}
|
|
3615
4008
|
/**
|
|
3616
4009
|
* Wrapper function to make a request to the record scanner service and handle any errors.
|
|
4010
|
+
* Optionally adds JWT Authorization header when consumerId/jwtData (or apiKey+consumerId) are configured.
|
|
3617
4011
|
*
|
|
3618
4012
|
* @param {Request} req The request to make.
|
|
3619
4013
|
* @returns {Promise<Response>} The response.
|
|
3620
4014
|
*/
|
|
3621
4015
|
async request(req) {
|
|
3622
4016
|
try {
|
|
4017
|
+
const authHeaders = await this.getAuthHeaders();
|
|
4018
|
+
for (const [key, value] of Object.entries(authHeaders)) {
|
|
4019
|
+
req.headers.set(key, value);
|
|
4020
|
+
}
|
|
3623
4021
|
if (this.apiKey) {
|
|
3624
4022
|
req.headers.set(this.apiKey.header, this.apiKey.value);
|
|
3625
4023
|
}
|
|
3626
4024
|
const response = await fetch(req);
|
|
3627
4025
|
if (!response.ok) {
|
|
3628
|
-
|
|
4026
|
+
const text = await response.text();
|
|
4027
|
+
throw new RecordScannerRequestError(text || `Request to ${req.url} failed with status ${response.status}`, response.status);
|
|
3629
4028
|
}
|
|
3630
4029
|
return response;
|
|
3631
4030
|
}
|
|
@@ -6623,5 +7022,5 @@ async function initializeWasm() {
|
|
|
6623
7022
|
console.warn("initializeWasm is deprecated, you no longer need to use it");
|
|
6624
7023
|
}
|
|
6625
7024
|
|
|
6626
|
-
export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KEY_STORE, 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, RecordScanner, SealanceMerkleTree, VALID_TRANSFER_TYPES, initializeWasm, logAndThrow };
|
|
7025
|
+
export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KEY_STORE, 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, RecordScanner, SealanceMerkleTree, VALID_TRANSFER_TYPES, encryptAuthorization, encryptProvingRequest, encryptRegistrationRequest, encryptViewKey, initializeWasm, isProveApiErrorBody, isProvingResponse, logAndThrow };
|
|
6627
7026
|
//# sourceMappingURL=browser.js.map
|