@provablehq/sdk 0.9.12 → 0.9.14
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/browser.js +743 -142
- package/dist/mainnet/browser.js.map +1 -1
- package/dist/mainnet/constants.d.ts +1 -0
- package/dist/mainnet/integrations/sealance/merkle-tree.d.ts +83 -12
- package/dist/mainnet/network-client.d.ts +29 -2
- package/dist/mainnet/node-polyfill.js.map +1 -1
- package/dist/mainnet/program-manager.d.ts +165 -0
- package/dist/testnet/browser.js +743 -142
- package/dist/testnet/browser.js.map +1 -1
- package/dist/testnet/constants.d.ts +1 -0
- package/dist/testnet/integrations/sealance/merkle-tree.d.ts +83 -12
- package/dist/testnet/network-client.d.ts +29 -2
- package/dist/testnet/node-polyfill.js.map +1 -1
- package/dist/testnet/program-manager.d.ts +165 -0
- package/package.json +2 -2
package/dist/mainnet/browser.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import 'core-js/proposals/json-parse-with-source.js';
|
|
2
|
-
import { ViewKey, ComputeKey, Address, PrivateKeyCiphertext, PrivateKey, RecordCiphertext, EncryptionToolkit, Group, Program, Plaintext, Transaction, ProvingRequest,
|
|
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
4
|
import { bech32m } from '@scure/base';
|
|
5
5
|
|
|
@@ -466,6 +466,106 @@ async function retryWithBackoff(fn, { maxAttempts = 5, baseDelay = 100, jitter,
|
|
|
466
466
|
throw new Error("retryWithBackoff: unreachable");
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
+
const KEY_STORE = Metadata.baseUrl();
|
|
470
|
+
function convert(metadata) {
|
|
471
|
+
// This looks up the method name in VerifyingKey
|
|
472
|
+
const verifyingKey = VerifyingKey[metadata.verifyingKey];
|
|
473
|
+
if (!verifyingKey) {
|
|
474
|
+
throw new Error("Invalid method name: " + metadata.verifyingKey);
|
|
475
|
+
}
|
|
476
|
+
return {
|
|
477
|
+
name: metadata.name,
|
|
478
|
+
locator: metadata.locator,
|
|
479
|
+
prover: metadata.prover,
|
|
480
|
+
verifier: metadata.verifier,
|
|
481
|
+
verifyingKey,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
const CREDITS_PROGRAM_KEYS = {
|
|
485
|
+
bond_public: convert(Metadata.bond_public()),
|
|
486
|
+
bond_validator: convert(Metadata.bond_validator()),
|
|
487
|
+
claim_unbond_public: convert(Metadata.claim_unbond_public()),
|
|
488
|
+
fee_private: convert(Metadata.fee_private()),
|
|
489
|
+
fee_public: convert(Metadata.fee_public()),
|
|
490
|
+
inclusion: convert(Metadata.inclusion()),
|
|
491
|
+
join: convert(Metadata.join()),
|
|
492
|
+
set_validator_state: convert(Metadata.set_validator_state()),
|
|
493
|
+
split: convert(Metadata.split()),
|
|
494
|
+
transfer_private: convert(Metadata.transfer_private()),
|
|
495
|
+
transfer_private_to_public: convert(Metadata.transfer_private_to_public()),
|
|
496
|
+
transfer_public: convert(Metadata.transfer_public()),
|
|
497
|
+
transfer_public_as_signer: convert(Metadata.transfer_public_as_signer()),
|
|
498
|
+
transfer_public_to_private: convert(Metadata.transfer_public_to_private()),
|
|
499
|
+
unbond_public: convert(Metadata.unbond_public()),
|
|
500
|
+
getKey: function (key) {
|
|
501
|
+
if (this.hasOwnProperty(key)) {
|
|
502
|
+
return this[key];
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
throw new Error(`Key "${key}" not found.`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
const PRIVATE_TRANSFER_TYPES = new Set([
|
|
510
|
+
"transfer_private",
|
|
511
|
+
"private",
|
|
512
|
+
"transferPrivate",
|
|
513
|
+
"transfer_private_to_public",
|
|
514
|
+
"privateToPublic",
|
|
515
|
+
"transferPrivateToPublic",
|
|
516
|
+
]);
|
|
517
|
+
const VALID_TRANSFER_TYPES = new Set([
|
|
518
|
+
"transfer_private",
|
|
519
|
+
"private",
|
|
520
|
+
"transferPrivate",
|
|
521
|
+
"transfer_private_to_public",
|
|
522
|
+
"privateToPublic",
|
|
523
|
+
"transferPrivateToPublic",
|
|
524
|
+
"transfer_public",
|
|
525
|
+
"transfer_public_as_signer",
|
|
526
|
+
"public",
|
|
527
|
+
"public_as_signer",
|
|
528
|
+
"transferPublic",
|
|
529
|
+
"transferPublicAsSigner",
|
|
530
|
+
"transfer_public_to_private",
|
|
531
|
+
"publicToPrivate",
|
|
532
|
+
"publicAsSigner",
|
|
533
|
+
"transferPublicToPrivate",
|
|
534
|
+
]);
|
|
535
|
+
const PRIVATE_TRANSFER = new Set([
|
|
536
|
+
"private",
|
|
537
|
+
"transfer_private",
|
|
538
|
+
"transferPrivate",
|
|
539
|
+
]);
|
|
540
|
+
const PRIVATE_TO_PUBLIC_TRANSFER = new Set([
|
|
541
|
+
"private_to_public",
|
|
542
|
+
"privateToPublic",
|
|
543
|
+
"transfer_private_to_public",
|
|
544
|
+
"transferPrivateToPublic",
|
|
545
|
+
]);
|
|
546
|
+
const PUBLIC_TRANSFER = new Set([
|
|
547
|
+
"public",
|
|
548
|
+
"transfer_public",
|
|
549
|
+
"transferPublic",
|
|
550
|
+
]);
|
|
551
|
+
const PUBLIC_TRANSFER_AS_SIGNER = new Set([
|
|
552
|
+
"public_as_signer",
|
|
553
|
+
"transfer_public_as_signer",
|
|
554
|
+
"transferPublicAsSigner",
|
|
555
|
+
]);
|
|
556
|
+
const PUBLIC_TO_PRIVATE_TRANSFER = new Set([
|
|
557
|
+
"public_to_private",
|
|
558
|
+
"publicToPrivate",
|
|
559
|
+
"transfer_public_to_private",
|
|
560
|
+
"transferPublicToPrivate",
|
|
561
|
+
]);
|
|
562
|
+
const RECORD_DOMAIN = "RecordScannerV0";
|
|
563
|
+
/**
|
|
564
|
+
* Zero address on Aleo blockchain that corresponds to field element 0. Used as padding in Merkle trees and as a sentinel value.
|
|
565
|
+
*/
|
|
566
|
+
const ZERO_ADDRESS = "aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc";
|
|
567
|
+
const FIVE_MINUTES = 5 * 60 * 1000; // 5 minutes in milliseconds
|
|
568
|
+
|
|
469
569
|
/**
|
|
470
570
|
* Client library that encapsulates REST calls to publicly exposed endpoints of Aleo nodes. The methods provided in this
|
|
471
571
|
* allow users to query public information from the Aleo blockchain and submit transactions to the network.
|
|
@@ -477,6 +577,8 @@ async function retryWithBackoff(fn, { maxAttempts = 5, baseDelay = 100, jitter,
|
|
|
477
577
|
*
|
|
478
578
|
* // Connection to a public beacon node
|
|
479
579
|
* const account = Account.fromCiphertext(process.env.ciphertext, process.env.password);
|
|
580
|
+
* const apiKey = process.env.apiKey;
|
|
581
|
+
* const consumerId = process.env.consumerId;
|
|
480
582
|
* const publicNetworkClient = new AleoNetworkClient("http://api.explorer.provable.com/v1", undefined, account);
|
|
481
583
|
*/
|
|
482
584
|
class AleoNetworkClient {
|
|
@@ -486,6 +588,9 @@ class AleoNetworkClient {
|
|
|
486
588
|
ctx;
|
|
487
589
|
verboseErrors;
|
|
488
590
|
network;
|
|
591
|
+
apiKey;
|
|
592
|
+
consumerId;
|
|
593
|
+
jwtData;
|
|
489
594
|
constructor(host, options) {
|
|
490
595
|
this.host = host + "/mainnet";
|
|
491
596
|
this.network = "mainnet";
|
|
@@ -497,7 +602,7 @@ class AleoNetworkClient {
|
|
|
497
602
|
else {
|
|
498
603
|
this.headers = {
|
|
499
604
|
// This is replaced by the actual version by a Rollup plugin
|
|
500
|
-
"X-Aleo-SDK-Version": "0.9.
|
|
605
|
+
"X-Aleo-SDK-Version": "0.9.14",
|
|
501
606
|
"X-Aleo-environment": environment(),
|
|
502
607
|
};
|
|
503
608
|
}
|
|
@@ -1342,10 +1447,9 @@ class AleoNetworkClient {
|
|
|
1342
1447
|
* programImports = await networkClient.getProgramImports(double_test);
|
|
1343
1448
|
* assert.deepStrictEqual(programImports, expectedImports);
|
|
1344
1449
|
*/
|
|
1345
|
-
async getProgramImports(inputProgram) {
|
|
1450
|
+
async getProgramImports(inputProgram, imports = {}) {
|
|
1346
1451
|
try {
|
|
1347
1452
|
this.ctx = { "X-ALEO-METHOD": "getProgramImports" };
|
|
1348
|
-
const imports = {};
|
|
1349
1453
|
// Normalize input to a Program object
|
|
1350
1454
|
let program;
|
|
1351
1455
|
if (inputProgram instanceof Program) {
|
|
@@ -1371,7 +1475,7 @@ class AleoNetworkClient {
|
|
|
1371
1475
|
const import_id = importList[i];
|
|
1372
1476
|
if (!imports.hasOwnProperty(import_id)) {
|
|
1373
1477
|
const programSource = await this.getProgram(import_id);
|
|
1374
|
-
const nestedImports = await this.getProgramImports(
|
|
1478
|
+
const nestedImports = await this.getProgramImports(programSource, imports);
|
|
1375
1479
|
for (const key in nestedImports) {
|
|
1376
1480
|
if (!imports.hasOwnProperty(key)) {
|
|
1377
1481
|
imports[key] = nestedImports[key];
|
|
@@ -1841,6 +1945,32 @@ class AleoNetworkClient {
|
|
|
1841
1945
|
throw new Error(`Error posting solution: No response received: ${error.message}`);
|
|
1842
1946
|
}
|
|
1843
1947
|
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Refreshes the JWT by making a POST request to /jwts/{consumer_id}
|
|
1950
|
+
*
|
|
1951
|
+
* @param {string} apiKey - The API key for authentication.
|
|
1952
|
+
* @param {string} consumerId - The consumer ID associated with the API key.
|
|
1953
|
+
* @returns {Promise<JwtData>} The JWT token and expiration time
|
|
1954
|
+
*/
|
|
1955
|
+
async refreshJwt(apiKey, consumerId) {
|
|
1956
|
+
if (!apiKey || !consumerId) {
|
|
1957
|
+
throw new Error('API key and consumer ID are required to refresh JWT');
|
|
1958
|
+
}
|
|
1959
|
+
const response = await post(`https://api.provable.com/jwts/${consumerId}`, {
|
|
1960
|
+
headers: {
|
|
1961
|
+
'X-Provable-API-Key': apiKey
|
|
1962
|
+
}
|
|
1963
|
+
});
|
|
1964
|
+
const authHeader = response.headers.get('authorization');
|
|
1965
|
+
if (!authHeader) {
|
|
1966
|
+
throw new Error('No authorization header in JWT refresh response');
|
|
1967
|
+
}
|
|
1968
|
+
const body = await response.json();
|
|
1969
|
+
return {
|
|
1970
|
+
jwt: authHeader,
|
|
1971
|
+
expiration: body.exp * 1000 // Convert to milliseconds
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1844
1974
|
/**
|
|
1845
1975
|
* 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.
|
|
1846
1976
|
*
|
|
@@ -1852,18 +1982,33 @@ class AleoNetworkClient {
|
|
|
1852
1982
|
const provingRequestString = options.provingRequest instanceof ProvingRequest
|
|
1853
1983
|
? options.provingRequest.toString()
|
|
1854
1984
|
: options.provingRequest;
|
|
1855
|
-
|
|
1985
|
+
const apiKey = options.apiKey ?? this.apiKey;
|
|
1986
|
+
const consumerId = options.consumerId ?? this.consumerId;
|
|
1987
|
+
let jwtData = options.jwtData ?? this.jwtData;
|
|
1988
|
+
// Check if JWT is expired or missing
|
|
1989
|
+
const bufferTime = FIVE_MINUTES; // 5 minutes buffer
|
|
1990
|
+
const isExpired = jwtData && Date.now() >= jwtData.expiration - bufferTime;
|
|
1991
|
+
if (!jwtData || isExpired) {
|
|
1992
|
+
if (options.apiKey && options.consumerId) {
|
|
1993
|
+
jwtData = await this.refreshJwt(apiKey, consumerId);
|
|
1994
|
+
// Update both the class and the options with the new JWT
|
|
1995
|
+
this.jwtData = jwtData;
|
|
1996
|
+
options.jwtData = jwtData;
|
|
1997
|
+
}
|
|
1998
|
+
else {
|
|
1999
|
+
throw new Error('JWT or both apiKey and consumerId are required');
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
1856
2002
|
const headers = {
|
|
1857
2003
|
...this.headers,
|
|
1858
2004
|
"X-ALEO-METHOD": "submitProvingRequest",
|
|
1859
|
-
"Content-Type": "application/json"
|
|
2005
|
+
"Content-Type": "application/json",
|
|
1860
2006
|
};
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
headers["X-Provable-API-Key"] = options.apiKey;
|
|
2007
|
+
if (jwtData?.jwt) {
|
|
2008
|
+
headers["Authorization"] = jwtData.jwt;
|
|
1864
2009
|
}
|
|
1865
2010
|
try {
|
|
1866
|
-
const response = await retryWithBackoff(() => post(`${proverUri}
|
|
2011
|
+
const response = await retryWithBackoff(() => post(`${proverUri}`, {
|
|
1867
2012
|
body: provingRequestString,
|
|
1868
2013
|
headers
|
|
1869
2014
|
}));
|
|
@@ -1957,105 +2102,6 @@ class AleoNetworkClient {
|
|
|
1957
2102
|
}
|
|
1958
2103
|
}
|
|
1959
2104
|
|
|
1960
|
-
const KEY_STORE = Metadata.baseUrl();
|
|
1961
|
-
function convert(metadata) {
|
|
1962
|
-
// This looks up the method name in VerifyingKey
|
|
1963
|
-
const verifyingKey = VerifyingKey[metadata.verifyingKey];
|
|
1964
|
-
if (!verifyingKey) {
|
|
1965
|
-
throw new Error("Invalid method name: " + metadata.verifyingKey);
|
|
1966
|
-
}
|
|
1967
|
-
return {
|
|
1968
|
-
name: metadata.name,
|
|
1969
|
-
locator: metadata.locator,
|
|
1970
|
-
prover: metadata.prover,
|
|
1971
|
-
verifier: metadata.verifier,
|
|
1972
|
-
verifyingKey,
|
|
1973
|
-
};
|
|
1974
|
-
}
|
|
1975
|
-
const CREDITS_PROGRAM_KEYS = {
|
|
1976
|
-
bond_public: convert(Metadata.bond_public()),
|
|
1977
|
-
bond_validator: convert(Metadata.bond_validator()),
|
|
1978
|
-
claim_unbond_public: convert(Metadata.claim_unbond_public()),
|
|
1979
|
-
fee_private: convert(Metadata.fee_private()),
|
|
1980
|
-
fee_public: convert(Metadata.fee_public()),
|
|
1981
|
-
inclusion: convert(Metadata.inclusion()),
|
|
1982
|
-
join: convert(Metadata.join()),
|
|
1983
|
-
set_validator_state: convert(Metadata.set_validator_state()),
|
|
1984
|
-
split: convert(Metadata.split()),
|
|
1985
|
-
transfer_private: convert(Metadata.transfer_private()),
|
|
1986
|
-
transfer_private_to_public: convert(Metadata.transfer_private_to_public()),
|
|
1987
|
-
transfer_public: convert(Metadata.transfer_public()),
|
|
1988
|
-
transfer_public_as_signer: convert(Metadata.transfer_public_as_signer()),
|
|
1989
|
-
transfer_public_to_private: convert(Metadata.transfer_public_to_private()),
|
|
1990
|
-
unbond_public: convert(Metadata.unbond_public()),
|
|
1991
|
-
getKey: function (key) {
|
|
1992
|
-
if (this.hasOwnProperty(key)) {
|
|
1993
|
-
return this[key];
|
|
1994
|
-
}
|
|
1995
|
-
else {
|
|
1996
|
-
throw new Error(`Key "${key}" not found.`);
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
};
|
|
2000
|
-
const PRIVATE_TRANSFER_TYPES = new Set([
|
|
2001
|
-
"transfer_private",
|
|
2002
|
-
"private",
|
|
2003
|
-
"transferPrivate",
|
|
2004
|
-
"transfer_private_to_public",
|
|
2005
|
-
"privateToPublic",
|
|
2006
|
-
"transferPrivateToPublic",
|
|
2007
|
-
]);
|
|
2008
|
-
const VALID_TRANSFER_TYPES = new Set([
|
|
2009
|
-
"transfer_private",
|
|
2010
|
-
"private",
|
|
2011
|
-
"transferPrivate",
|
|
2012
|
-
"transfer_private_to_public",
|
|
2013
|
-
"privateToPublic",
|
|
2014
|
-
"transferPrivateToPublic",
|
|
2015
|
-
"transfer_public",
|
|
2016
|
-
"transfer_public_as_signer",
|
|
2017
|
-
"public",
|
|
2018
|
-
"public_as_signer",
|
|
2019
|
-
"transferPublic",
|
|
2020
|
-
"transferPublicAsSigner",
|
|
2021
|
-
"transfer_public_to_private",
|
|
2022
|
-
"publicToPrivate",
|
|
2023
|
-
"publicAsSigner",
|
|
2024
|
-
"transferPublicToPrivate",
|
|
2025
|
-
]);
|
|
2026
|
-
const PRIVATE_TRANSFER = new Set([
|
|
2027
|
-
"private",
|
|
2028
|
-
"transfer_private",
|
|
2029
|
-
"transferPrivate",
|
|
2030
|
-
]);
|
|
2031
|
-
const PRIVATE_TO_PUBLIC_TRANSFER = new Set([
|
|
2032
|
-
"private_to_public",
|
|
2033
|
-
"privateToPublic",
|
|
2034
|
-
"transfer_private_to_public",
|
|
2035
|
-
"transferPrivateToPublic",
|
|
2036
|
-
]);
|
|
2037
|
-
const PUBLIC_TRANSFER = new Set([
|
|
2038
|
-
"public",
|
|
2039
|
-
"transfer_public",
|
|
2040
|
-
"transferPublic",
|
|
2041
|
-
]);
|
|
2042
|
-
const PUBLIC_TRANSFER_AS_SIGNER = new Set([
|
|
2043
|
-
"public_as_signer",
|
|
2044
|
-
"transfer_public_as_signer",
|
|
2045
|
-
"transferPublicAsSigner",
|
|
2046
|
-
]);
|
|
2047
|
-
const PUBLIC_TO_PRIVATE_TRANSFER = new Set([
|
|
2048
|
-
"public_to_private",
|
|
2049
|
-
"publicToPrivate",
|
|
2050
|
-
"transfer_public_to_private",
|
|
2051
|
-
"transferPublicToPrivate",
|
|
2052
|
-
]);
|
|
2053
|
-
const RECORD_DOMAIN = "RecordScannerV0";
|
|
2054
|
-
/**
|
|
2055
|
-
* Zero address on Aleo blockchain that corresponds to field element 0. Used as padding in Merkle trees and as a sentinel value.
|
|
2056
|
-
*/
|
|
2057
|
-
const ZERO_ADDRESS = "aleo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc";
|
|
2058
|
-
|
|
2059
2105
|
/**
|
|
2060
2106
|
* AleoKeyProviderParams search parameter for the AleoKeyProvider. It allows for the specification of a proverUri and
|
|
2061
2107
|
* verifierUri to fetch keys via HTTP from a remote resource as well as a unique cacheKey to store the keys in memory.
|
|
@@ -3616,6 +3662,7 @@ class RecordScanner {
|
|
|
3616
3662
|
* const proof_left = sealance.getSiblingPath(tree, leftIdx, 15);
|
|
3617
3663
|
* const proof_right = sealance.getSiblingPath(tree, rightIdx, 15);
|
|
3618
3664
|
* const exclusion_proof = [proof_left, proof_right];
|
|
3665
|
+
* const formatted_proof = sealance.formatMerkleProof(exclusion_proof);
|
|
3619
3666
|
* ```
|
|
3620
3667
|
*/
|
|
3621
3668
|
class SealanceMerkleTree {
|
|
@@ -3633,8 +3680,9 @@ class SealanceMerkleTree {
|
|
|
3633
3680
|
*
|
|
3634
3681
|
* @example
|
|
3635
3682
|
* ```typescript
|
|
3683
|
+
* const sealance = new SealanceMerkleTree();
|
|
3636
3684
|
* const address = "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px";
|
|
3637
|
-
* const fieldValue = convertAddressToField(address);
|
|
3685
|
+
* const fieldValue = sealance.convertAddressToField(address);
|
|
3638
3686
|
* console.log(fieldValue); // 123456789...n
|
|
3639
3687
|
* ```
|
|
3640
3688
|
*/
|
|
@@ -3673,8 +3721,9 @@ class SealanceMerkleTree {
|
|
|
3673
3721
|
*
|
|
3674
3722
|
* @example
|
|
3675
3723
|
* ```typescript
|
|
3724
|
+
* const sealance = new SealanceMerkleTree();
|
|
3676
3725
|
* const leaves = ["0field", "1field", "2field", "3field"];
|
|
3677
|
-
* const tree = buildTree(leaves);
|
|
3726
|
+
* const tree = sealance.buildTree(leaves);
|
|
3678
3727
|
* const root = tree[tree.length - 1]; // Get the Merkle root
|
|
3679
3728
|
* ```
|
|
3680
3729
|
*/
|
|
@@ -3704,6 +3753,35 @@ class SealanceMerkleTree {
|
|
|
3704
3753
|
return tree.map(element => BigInt(element.slice(0, element.length - "field".length)));
|
|
3705
3754
|
}
|
|
3706
3755
|
/**
|
|
3756
|
+
* Converts an array of decimal string representations of U256 numbers to an array of BigInts.
|
|
3757
|
+
*
|
|
3758
|
+
* @param tree - Array of decimal string representations of U256 numbers.
|
|
3759
|
+
* @returns Array of BigInts.
|
|
3760
|
+
*
|
|
3761
|
+
* @example
|
|
3762
|
+
* ```typescript
|
|
3763
|
+
* const treeStrings = ["0","4328470178059738374782465505490977516512210899136548187530607227309847251692","1741259420362056497457198439964202806733137875365061915996980524089960046336"];
|
|
3764
|
+
* const sealance = new SealanceMerkleTree();
|
|
3765
|
+
* const treeBigInts = sealance.convertTreeToBigInt(treeStrings);
|
|
3766
|
+
* console.log(treeBigInts); // [
|
|
3767
|
+
* 0,
|
|
3768
|
+
* 4328470178059738374782465505490977516512210899136548187530607227309847251692,
|
|
3769
|
+
* 1741259420362056497457198439964202806733137875365061915996980524089960046336
|
|
3770
|
+
* ]
|
|
3771
|
+
* ```
|
|
3772
|
+
*/
|
|
3773
|
+
convertTreeToBigInt(tree) {
|
|
3774
|
+
return tree.map((element) => {
|
|
3775
|
+
try {
|
|
3776
|
+
// decimal string → native bigint
|
|
3777
|
+
return BigInt(element);
|
|
3778
|
+
}
|
|
3779
|
+
catch {
|
|
3780
|
+
throw new Error(`Invalid decimal U256 string: ${element}`);
|
|
3781
|
+
}
|
|
3782
|
+
});
|
|
3783
|
+
}
|
|
3784
|
+
/**
|
|
3707
3785
|
* Converts Aleo addresses to field elements, sorts them, pads with zero fields, and returns an array. This prepares addresses for Merkle tree construction.
|
|
3708
3786
|
*
|
|
3709
3787
|
* @param addresses - Array of Aleo addresses.
|
|
@@ -3714,11 +3792,18 @@ class SealanceMerkleTree {
|
|
|
3714
3792
|
* @example
|
|
3715
3793
|
* ```typescript
|
|
3716
3794
|
* const addresses = [
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
* const
|
|
3795
|
+
* "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px",
|
|
3796
|
+
* "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t",
|
|
3797
|
+
* "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t",
|
|
3798
|
+
* ];
|
|
3799
|
+
* const sealance = new SealanceMerkleTree();
|
|
3800
|
+
* const leaves = sealance.generateLeaves(addresses, 15);
|
|
3801
|
+
* console.log(leaves); // [
|
|
3802
|
+
* "0field",
|
|
3803
|
+
* "1295133970529764960316948294624974168921228814652993007266766481909235735940field",
|
|
3804
|
+
* "1295133970529764960316948294624974168921228814652993007266766481909235735940field",
|
|
3805
|
+
* "3501665755452795161867664882580888971213780722176652848275908626939553697821field"
|
|
3806
|
+
* ]
|
|
3722
3807
|
* ```
|
|
3723
3808
|
*/
|
|
3724
3809
|
generateLeaves(addresses, maxTreeDepth = 15) {
|
|
@@ -3757,8 +3842,15 @@ class SealanceMerkleTree {
|
|
|
3757
3842
|
*
|
|
3758
3843
|
* @example
|
|
3759
3844
|
* ```typescript
|
|
3760
|
-
* const
|
|
3761
|
-
|
|
3845
|
+
* const addresses = [
|
|
3846
|
+
* "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px",
|
|
3847
|
+
* "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t",
|
|
3848
|
+
* "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t",
|
|
3849
|
+
* ];
|
|
3850
|
+
* const sealance = new SealanceMerkleTree();
|
|
3851
|
+
* const leaves = sealance.generateLeaves(addresses);
|
|
3852
|
+
* const tree = sealance.buildTree(leaves);
|
|
3853
|
+
* const [leftIdx, rightIdx] = sealance.getLeafIndices(tree, "aleo1...");
|
|
3762
3854
|
* ```
|
|
3763
3855
|
*/
|
|
3764
3856
|
getLeafIndices(merkleTree, address) {
|
|
@@ -3786,9 +3878,17 @@ class SealanceMerkleTree {
|
|
|
3786
3878
|
*
|
|
3787
3879
|
* @example
|
|
3788
3880
|
* ```typescript
|
|
3789
|
-
* const
|
|
3790
|
-
*
|
|
3791
|
-
*
|
|
3881
|
+
* const addresses = [
|
|
3882
|
+
* "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px",
|
|
3883
|
+
* "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t",
|
|
3884
|
+
* "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t",
|
|
3885
|
+
* ];
|
|
3886
|
+
* const sealance = new SealanceMerkleTree();
|
|
3887
|
+
* const leaves = sealance.generateLeaves(addresses);
|
|
3888
|
+
* const tree = sealance.buildTree(leaves);
|
|
3889
|
+
* const [leftIdx, rightIdx] = sealance.getLeafIndices(tree, "aleo1...");
|
|
3890
|
+
* const proof = sealance.getSiblingPath(tree, leftIdx, 15);
|
|
3891
|
+
* // proof = { siblings: [0n, 1n, ...], leaf_index: leftIdx }
|
|
3792
3892
|
* ```
|
|
3793
3893
|
*/
|
|
3794
3894
|
getSiblingPath(tree, leafIndex, depth) {
|
|
@@ -3811,6 +3911,36 @@ class SealanceMerkleTree {
|
|
|
3811
3911
|
}
|
|
3812
3912
|
return { siblings: siblingPath, leaf_index: leafIndex };
|
|
3813
3913
|
}
|
|
3914
|
+
/**
|
|
3915
|
+
* Generates a formatted exclusion proof suitable for Aleo transactions.
|
|
3916
|
+
*
|
|
3917
|
+
* @param proof - An array of two {sibling path, leafindex} objects.
|
|
3918
|
+
* @returns String representation of the exclusion proof.
|
|
3919
|
+
*
|
|
3920
|
+
* @example
|
|
3921
|
+
* ```typescript
|
|
3922
|
+
* const addresses = [
|
|
3923
|
+
* "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px",
|
|
3924
|
+
* "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t",
|
|
3925
|
+
* "aleo1s3ws5tra87fjycnjrwsjcrnw2qxr8jfqqdugnf0xzqqw29q9m5pqem2u4t",
|
|
3926
|
+
* ];
|
|
3927
|
+
* const sealance = new SealanceMerkleTree();
|
|
3928
|
+
* const leaves = sealance.generateLeaves(addresses);
|
|
3929
|
+
* const tree = sealance.buildTree(leaves);
|
|
3930
|
+
* const [leftIdx, rightIdx] = sealance.getLeafIndices(tree, "aleo1...");
|
|
3931
|
+
* const proof1 = getSiblingPath(tree, leftIdx, 15);
|
|
3932
|
+
* const proof2 = getSiblingPath(tree, rightIdx, 15);
|
|
3933
|
+
* const formattedProof = formatMerkleProof([proof1, proof2]);
|
|
3934
|
+
* // formattedProof = "[{ siblings: [0field, 1field, ...], leaf_index: 0u32 }, { siblings: [0field, 2field, ...], leaf_index: 1u32 }]"
|
|
3935
|
+
* ```
|
|
3936
|
+
*/
|
|
3937
|
+
formatMerkleProof(proof) {
|
|
3938
|
+
const formatted = proof.map(item => {
|
|
3939
|
+
const siblings = item.siblings.map(s => `${s}field`).join(", ");
|
|
3940
|
+
return `{siblings: [${siblings}], leaf_index: ${item.leaf_index}u32}`;
|
|
3941
|
+
}).join(", ");
|
|
3942
|
+
return `[${formatted}]`;
|
|
3943
|
+
}
|
|
3814
3944
|
}
|
|
3815
3945
|
|
|
3816
3946
|
/**
|
|
@@ -4069,21 +4199,15 @@ class ProgramManager {
|
|
|
4069
4199
|
return await ProgramManager$1.buildDeploymentTransaction(deploymentPrivateKey, program, priorityFee, feeRecord, this.host, imports, feeProvingKey, feeVerifyingKey);
|
|
4070
4200
|
}
|
|
4071
4201
|
/**
|
|
4072
|
-
*
|
|
4202
|
+
* Builds a deployment transaction for submission to the Aleo network that upgrades an existing program.
|
|
4073
4203
|
*
|
|
4074
|
-
* @param {
|
|
4075
|
-
* @param {number} priorityFee The optional fee to be paid for the transaction
|
|
4076
|
-
* @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance
|
|
4077
|
-
* @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for searching for a record to used pay the deployment fee
|
|
4078
|
-
* @param {string | RecordPlaintext | undefined} feeRecord Optional Fee record to use for the transaction
|
|
4079
|
-
* @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction
|
|
4080
|
-
* @returns {string} The transaction id of the deployed program or a failure message from the network
|
|
4204
|
+
* @param {DeployOptions} options The deployment options.
|
|
4081
4205
|
*
|
|
4082
4206
|
* @example
|
|
4083
4207
|
* /// Import the mainnet version of the sdk.
|
|
4084
4208
|
* import { AleoKeyProvider, ProgramManager, NetworkRecordProvider } from "@provablehq/sdk/mainnet.js";
|
|
4085
4209
|
*
|
|
4086
|
-
* // Create a new NetworkClient, KeyProvider, and RecordProvider
|
|
4210
|
+
* // Create a new NetworkClient, KeyProvider, and RecordProvider
|
|
4087
4211
|
* const keyProvider = new AleoKeyProvider();
|
|
4088
4212
|
* const recordProvider = new NetworkRecordProvider(account, networkClient);
|
|
4089
4213
|
* keyProvider.useCache(true);
|
|
@@ -4091,12 +4215,130 @@ class ProgramManager {
|
|
|
4091
4215
|
* // Initialize a program manager with the key provider to automatically fetch keys for deployments
|
|
4092
4216
|
* const program = "program hello_hello.aleo;\n\nfunction hello:\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";
|
|
4093
4217
|
* const programManager = new ProgramManager("https://api.explorer.provable.com/v1", keyProvider, recordProvider);
|
|
4218
|
+
* programManager.setAccount(Account);
|
|
4094
4219
|
*
|
|
4095
4220
|
* // Define a fee in credits
|
|
4096
4221
|
* const priorityFee = 0.0;
|
|
4097
4222
|
*
|
|
4098
|
-
* //
|
|
4099
|
-
* const
|
|
4223
|
+
* // Create the deployment transaction.
|
|
4224
|
+
* const tx = await programManager.buildUpgradeTransaction({program: program, priorityFee: fee, privateFee: false});
|
|
4225
|
+
* await programManager.networkClient.submitTransaction(tx);
|
|
4226
|
+
*
|
|
4227
|
+
* // Verify the transaction was successful
|
|
4228
|
+
* setTimeout(async () => {
|
|
4229
|
+
* const transaction = await programManager.networkClient.getTransaction(tx.id());
|
|
4230
|
+
* assert(transaction.id() === tx.id());
|
|
4231
|
+
* }, 20000);
|
|
4232
|
+
*/
|
|
4233
|
+
async buildUpgradeTransaction(options) {
|
|
4234
|
+
const { program, priorityFee, privateFee, recordSearchParams } = options;
|
|
4235
|
+
let feeRecord = options.feeRecord;
|
|
4236
|
+
let privateKey = options.privateKey;
|
|
4237
|
+
// Ensure the program is valid.
|
|
4238
|
+
let programObject;
|
|
4239
|
+
try {
|
|
4240
|
+
programObject = Program.fromString(program);
|
|
4241
|
+
}
|
|
4242
|
+
catch (e) {
|
|
4243
|
+
logAndThrow(`Error parsing program: '${e.message}'. Please ensure the program is valid.`);
|
|
4244
|
+
}
|
|
4245
|
+
// Ensure the program is valid and does not exist on the network
|
|
4246
|
+
try {
|
|
4247
|
+
let programSource;
|
|
4248
|
+
try {
|
|
4249
|
+
programSource = await this.networkClient.getProgram(programObject.id());
|
|
4250
|
+
}
|
|
4251
|
+
catch (e) {
|
|
4252
|
+
// Program does not exist on the network, deployment can proceed
|
|
4253
|
+
console.log(`Program ${programObject.id()} does not exist on the network...`);
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4256
|
+
catch (e) {
|
|
4257
|
+
logAndThrow(`Error validating program: ${e.message}`);
|
|
4258
|
+
}
|
|
4259
|
+
// Get the private key from the account if it is not provided in the parameters
|
|
4260
|
+
let deploymentPrivateKey = privateKey;
|
|
4261
|
+
if (typeof privateKey === "undefined" &&
|
|
4262
|
+
typeof this.account !== "undefined") {
|
|
4263
|
+
deploymentPrivateKey = this.account.privateKey();
|
|
4264
|
+
}
|
|
4265
|
+
if (typeof deploymentPrivateKey === "undefined") {
|
|
4266
|
+
throw "No private key provided and no private key set in the ProgramManager";
|
|
4267
|
+
}
|
|
4268
|
+
// Get the fee record from the account if it is not provided in the parameters
|
|
4269
|
+
try {
|
|
4270
|
+
if (privateFee) {
|
|
4271
|
+
let fee = priorityFee;
|
|
4272
|
+
// If a private fee is specified, but no fee record is provided, estimate the fee and find a matching record.
|
|
4273
|
+
if (!feeRecord) {
|
|
4274
|
+
console.log("Private fee specified, but no private fee record provided, estimating fee and finding a matching fee record.");
|
|
4275
|
+
const programString = programObject.toString();
|
|
4276
|
+
const imports = await this.networkClient.getProgramImports(programString);
|
|
4277
|
+
const baseFee = Number(ProgramManager$1.estimateDeploymentFee(programString, imports));
|
|
4278
|
+
fee = baseFee + priorityFee;
|
|
4279
|
+
}
|
|
4280
|
+
// Get a credits.aleo record for the fee.
|
|
4281
|
+
feeRecord = await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams);
|
|
4282
|
+
}
|
|
4283
|
+
else {
|
|
4284
|
+
// If it's specified NOT to use a privateFee, use a public fee.
|
|
4285
|
+
feeRecord = undefined;
|
|
4286
|
+
}
|
|
4287
|
+
}
|
|
4288
|
+
catch (e) {
|
|
4289
|
+
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.`);
|
|
4290
|
+
}
|
|
4291
|
+
// Get the proving and verifying keys from the key provider
|
|
4292
|
+
let feeKeys;
|
|
4293
|
+
try {
|
|
4294
|
+
feeKeys = privateFee
|
|
4295
|
+
? await this.keyProvider.feePrivateKeys()
|
|
4296
|
+
: await this.keyProvider.feePublicKeys();
|
|
4297
|
+
}
|
|
4298
|
+
catch (e) {
|
|
4299
|
+
logAndThrow(`Error finding fee keys. Key finder response: '${e.message}'. Please ensure your key provider is configured correctly.`);
|
|
4300
|
+
}
|
|
4301
|
+
const [feeProvingKey, feeVerifyingKey] = feeKeys;
|
|
4302
|
+
// Resolve the program imports if they exist
|
|
4303
|
+
let imports;
|
|
4304
|
+
try {
|
|
4305
|
+
imports = await this.networkClient.getProgramImports(program);
|
|
4306
|
+
}
|
|
4307
|
+
catch (e) {
|
|
4308
|
+
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.`);
|
|
4309
|
+
}
|
|
4310
|
+
// Build a deployment transaction
|
|
4311
|
+
return await ProgramManager$1.buildUpgradeTransaction(deploymentPrivateKey, program, priorityFee, feeRecord, this.host, imports, feeProvingKey, feeVerifyingKey);
|
|
4312
|
+
}
|
|
4313
|
+
/**
|
|
4314
|
+
* Deploy an Aleo program to the Aleo network
|
|
4315
|
+
*
|
|
4316
|
+
* @param {string} program Program source code
|
|
4317
|
+
* @param {number} priorityFee The optional fee to be paid for the transaction
|
|
4318
|
+
* @param {boolean} privateFee Use a private record to pay the fee. If false this will use the account's public credit balance
|
|
4319
|
+
* @param {RecordSearchParams | undefined} recordSearchParams Optional parameters for searching for a record to used pay the deployment fee
|
|
4320
|
+
* @param {string | RecordPlaintext | undefined} feeRecord Optional Fee record to use for the transaction
|
|
4321
|
+
* @param {PrivateKey | undefined} privateKey Optional private key to use for the transaction
|
|
4322
|
+
* @returns {string} The transaction id of the deployed program or a failure message from the network
|
|
4323
|
+
*
|
|
4324
|
+
* @example
|
|
4325
|
+
* /// Import the mainnet version of the sdk.
|
|
4326
|
+
* import { AleoKeyProvider, ProgramManager, NetworkRecordProvider } from "@provablehq/sdk/mainnet.js";
|
|
4327
|
+
*
|
|
4328
|
+
* // Create a new NetworkClient, KeyProvider, and RecordProvider.
|
|
4329
|
+
* const keyProvider = new AleoKeyProvider();
|
|
4330
|
+
* const recordProvider = new NetworkRecordProvider(account, networkClient);
|
|
4331
|
+
* keyProvider.useCache(true);
|
|
4332
|
+
*
|
|
4333
|
+
* // Initialize a program manager with the key provider to automatically fetch keys for deployments
|
|
4334
|
+
* const program = "program hello_hello.aleo;\n\nfunction hello:\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";
|
|
4335
|
+
* const programManager = new ProgramManager("https://api.explorer.provable.com/v1", keyProvider, recordProvider);
|
|
4336
|
+
*
|
|
4337
|
+
* // Define a fee in credits
|
|
4338
|
+
* const priorityFee = 0.0;
|
|
4339
|
+
*
|
|
4340
|
+
* // Deploy the program
|
|
4341
|
+
* const tx_id = await programManager.deploy(program, fee, false);
|
|
4100
4342
|
*
|
|
4101
4343
|
* // Verify the transaction was successful
|
|
4102
4344
|
* setTimeout(async () => {
|
|
@@ -4117,7 +4359,9 @@ class ProgramManager {
|
|
|
4117
4359
|
throw Error("No private key provided and no private key set in the ProgramManager. Please set an account or provide a private key.");
|
|
4118
4360
|
}
|
|
4119
4361
|
// Check if the account has sufficient credits to pay for the transaction
|
|
4120
|
-
|
|
4362
|
+
if (!privateFee) {
|
|
4363
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
4364
|
+
}
|
|
4121
4365
|
return await this.networkClient.submitTransaction(tx);
|
|
4122
4366
|
}
|
|
4123
4367
|
/**
|
|
@@ -4788,7 +5032,9 @@ class ProgramManager {
|
|
|
4788
5032
|
throw Error("No private key provided and no private key set in the ProgramManager. Please set an account or provide a private key.");
|
|
4789
5033
|
}
|
|
4790
5034
|
// Check if the account has sufficient credits to pay for the transaction
|
|
4791
|
-
|
|
5035
|
+
if (!options.privateFee) {
|
|
5036
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
5037
|
+
}
|
|
4792
5038
|
return await this.networkClient.submitTransaction(tx);
|
|
4793
5039
|
}
|
|
4794
5040
|
/**
|
|
@@ -4960,7 +5206,9 @@ class ProgramManager {
|
|
|
4960
5206
|
// Build an execution transaction and submit it to the network
|
|
4961
5207
|
const tx = await ProgramManager$1.buildJoinTransaction(executionPrivateKey, recordOne, recordTwo, priorityFee, feeRecord, this.host, joinProvingKey, joinVerifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery);
|
|
4962
5208
|
// Check if the account has sufficient credits to pay for the transaction
|
|
4963
|
-
|
|
5209
|
+
if (!privateFee) {
|
|
5210
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
5211
|
+
}
|
|
4964
5212
|
return await this.networkClient.submitTransaction(tx);
|
|
4965
5213
|
}
|
|
4966
5214
|
/**
|
|
@@ -5287,7 +5535,9 @@ class ProgramManager {
|
|
|
5287
5535
|
throw Error("No private key provided and no private key set in the ProgramManager. Please set an account or provide a private key.");
|
|
5288
5536
|
}
|
|
5289
5537
|
// Check if the account has sufficient credits to pay for the transaction
|
|
5290
|
-
|
|
5538
|
+
if (!privateFee) {
|
|
5539
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
5540
|
+
}
|
|
5291
5541
|
return await this.networkClient.submitTransaction(tx);
|
|
5292
5542
|
}
|
|
5293
5543
|
/**
|
|
@@ -5388,7 +5638,9 @@ class ProgramManager {
|
|
|
5388
5638
|
throw Error("No private key provided and no private key set in the ProgramManager. Please set an account or provide a private key.");
|
|
5389
5639
|
}
|
|
5390
5640
|
// Check if the account has sufficient credits to pay for the transaction
|
|
5391
|
-
|
|
5641
|
+
if (!options.privateFee) {
|
|
5642
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
5643
|
+
}
|
|
5392
5644
|
return await this.networkClient.submitTransaction(tx);
|
|
5393
5645
|
}
|
|
5394
5646
|
/**
|
|
@@ -5494,7 +5746,9 @@ class ProgramManager {
|
|
|
5494
5746
|
throw Error("No private key provided and no private key set in the ProgramManager. Please set an account or provide a private key.");
|
|
5495
5747
|
}
|
|
5496
5748
|
// Check if the account has sufficient credits to pay for the transaction
|
|
5497
|
-
|
|
5749
|
+
if (!options.privateFee) {
|
|
5750
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
5751
|
+
}
|
|
5498
5752
|
return await this.networkClient.submitTransaction(tx);
|
|
5499
5753
|
}
|
|
5500
5754
|
/**
|
|
@@ -5592,7 +5846,9 @@ class ProgramManager {
|
|
|
5592
5846
|
throw Error("No private key provided and no private key set in the ProgramManager. Please set an account or provide a private key.");
|
|
5593
5847
|
}
|
|
5594
5848
|
// Check if the account has sufficient credits to pay for the transaction
|
|
5595
|
-
|
|
5849
|
+
if (!options.privateFee) {
|
|
5850
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
5851
|
+
}
|
|
5596
5852
|
return await this.networkClient.submitTransaction(tx);
|
|
5597
5853
|
}
|
|
5598
5854
|
/**
|
|
@@ -5686,7 +5942,9 @@ class ProgramManager {
|
|
|
5686
5942
|
throw Error("No private key provided and no private key set in the ProgramManager. Please set an account or provide a private key.");
|
|
5687
5943
|
}
|
|
5688
5944
|
// Check if the account has sufficient credits to pay for the transaction
|
|
5689
|
-
|
|
5945
|
+
if (!options.privateFee) {
|
|
5946
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
5947
|
+
}
|
|
5690
5948
|
return await this.networkClient.submitTransaction(tx);
|
|
5691
5949
|
}
|
|
5692
5950
|
/**
|
|
@@ -5793,7 +6051,9 @@ class ProgramManager {
|
|
|
5793
6051
|
throw Error("No private key provided and no private key set in the ProgramManager. Please set an account or provide a private key.");
|
|
5794
6052
|
}
|
|
5795
6053
|
// Check if the account has sufficient credits to pay for the transaction
|
|
5796
|
-
|
|
6054
|
+
if (!options.privateFee) {
|
|
6055
|
+
await this.checkFee(feeAddress.to_string(), tx.feeAmount());
|
|
6056
|
+
}
|
|
5797
6057
|
return this.networkClient.submitTransaction(tx);
|
|
5798
6058
|
}
|
|
5799
6059
|
/**
|
|
@@ -6005,6 +6265,347 @@ class ProgramManager {
|
|
|
6005
6265
|
}
|
|
6006
6266
|
}
|
|
6007
6267
|
}
|
|
6268
|
+
/**
|
|
6269
|
+
* Builds an execution transaction for submission to the a local devnode.
|
|
6270
|
+
* This method skips proof generation and is not meant for use with the mainnet or testnet Aleo networks.
|
|
6271
|
+
* Note: getOrInitConsensusVersionTestHeights must be called prior to using this method for this method to work properly.
|
|
6272
|
+
*
|
|
6273
|
+
* @param {ExecuteOptions} options - The options for the execution transaction.
|
|
6274
|
+
* @returns {Promise<Transaction>} - A promise that resolves to the transaction or an error.
|
|
6275
|
+
*
|
|
6276
|
+
* @example
|
|
6277
|
+
* /// Import the mainnet version of the sdk.
|
|
6278
|
+
* import { AleoKeyProvider, getOrInitConsensusVersionTestHeights, ProgramManager, NetworkRecordProvider } from "@provablehq/sdk/mainnet.js";
|
|
6279
|
+
*
|
|
6280
|
+
* // Initialize the development consensus heights in order to work with devnode.
|
|
6281
|
+
* getOrInitConsensusVersionTestHeights("0,1,2,3,4,5,6,7,8,9,10,11");
|
|
6282
|
+
*
|
|
6283
|
+
* // Create a new NetworkClient and RecordProvider.
|
|
6284
|
+
* const recordProvider = new NetworkRecordProvider(account, networkClient);
|
|
6285
|
+
* keyProvider.useCache(true);
|
|
6286
|
+
*
|
|
6287
|
+
* // Initialize a program manager.
|
|
6288
|
+
* const programManager = new ProgramManager("http://localhost:3030", recordProvider);
|
|
6289
|
+
*
|
|
6290
|
+
* // Build and execute the transaction.
|
|
6291
|
+
* const tx = await programManager.buildDevnodeExecutionTransaction({
|
|
6292
|
+
* programName: "hello_hello.aleo",
|
|
6293
|
+
* functionName: "hello_hello",
|
|
6294
|
+
* priorityFee: 0.0,
|
|
6295
|
+
* privateFee: false,
|
|
6296
|
+
* inputs: ["5u32", "5u32"],
|
|
6297
|
+
* });
|
|
6298
|
+
*
|
|
6299
|
+
* // Submit the transaction to the network
|
|
6300
|
+
* await programManager.networkClient.submitTransaction(tx.toString());
|
|
6301
|
+
*
|
|
6302
|
+
* // Verify the transaction was successful
|
|
6303
|
+
* setTimeout(async () => {
|
|
6304
|
+
* const transaction = await programManager.networkClient.getTransaction(tx.id());
|
|
6305
|
+
* assert(transaction.id() === tx.id());
|
|
6306
|
+
* }, 10000);
|
|
6307
|
+
*/
|
|
6308
|
+
async buildDevnodeExecutionTransaction(options) {
|
|
6309
|
+
// Destructure the options object to access the parameters
|
|
6310
|
+
const { functionName, priorityFee, privateFee, inputs, recordSearchParams, privateKey, } = options;
|
|
6311
|
+
let feeRecord = options.feeRecord;
|
|
6312
|
+
let program = options.program;
|
|
6313
|
+
let programName = options.programName;
|
|
6314
|
+
let imports = options.imports;
|
|
6315
|
+
let edition = options.edition;
|
|
6316
|
+
let programObject;
|
|
6317
|
+
// Ensure the function exists on the network
|
|
6318
|
+
if (program === undefined) {
|
|
6319
|
+
try {
|
|
6320
|
+
programObject = await this.networkClient.getProgramObject(programName);
|
|
6321
|
+
program = programObject.toString();
|
|
6322
|
+
}
|
|
6323
|
+
catch (e) {
|
|
6324
|
+
logAndThrow(`Error finding ${programName}. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network the program is deployed to the network.`);
|
|
6325
|
+
}
|
|
6326
|
+
}
|
|
6327
|
+
else if (typeof program == "string") {
|
|
6328
|
+
try {
|
|
6329
|
+
programObject = Program.fromString(program);
|
|
6330
|
+
}
|
|
6331
|
+
catch (e) {
|
|
6332
|
+
logAndThrow(`Program sources passed for ${programName} were invalid: ${e}`);
|
|
6333
|
+
}
|
|
6334
|
+
}
|
|
6335
|
+
else if (program instanceof Program) {
|
|
6336
|
+
programObject = program;
|
|
6337
|
+
program = program.toString();
|
|
6338
|
+
}
|
|
6339
|
+
if (!(programObject instanceof Program)) {
|
|
6340
|
+
logAndThrow(`Failed to validate program ${programName}`);
|
|
6341
|
+
}
|
|
6342
|
+
// Get the program name if it is not provided in the parameters.
|
|
6343
|
+
if (programName === undefined) {
|
|
6344
|
+
programName = programObject.id();
|
|
6345
|
+
}
|
|
6346
|
+
if (edition == undefined) {
|
|
6347
|
+
try {
|
|
6348
|
+
edition = await this.networkClient.getLatestProgramEdition(programName);
|
|
6349
|
+
}
|
|
6350
|
+
catch (e) {
|
|
6351
|
+
console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
|
|
6352
|
+
edition = 0;
|
|
6353
|
+
}
|
|
6354
|
+
}
|
|
6355
|
+
// Get the private key from the account if it is not provided in the parameters.
|
|
6356
|
+
let executionPrivateKey = privateKey;
|
|
6357
|
+
if (typeof privateKey === "undefined" &&
|
|
6358
|
+
typeof this.account !== "undefined") {
|
|
6359
|
+
executionPrivateKey = this.account.privateKey();
|
|
6360
|
+
}
|
|
6361
|
+
if (typeof executionPrivateKey === "undefined") {
|
|
6362
|
+
throw "No private key provided and no private key set in the ProgramManager";
|
|
6363
|
+
}
|
|
6364
|
+
// Get the fee record from the account if it is not provided in the parameters.
|
|
6365
|
+
try {
|
|
6366
|
+
if (privateFee) {
|
|
6367
|
+
let fee = priorityFee;
|
|
6368
|
+
// If a private fee is specified, but no fee record is provided, estimate the fee and find a matching record.
|
|
6369
|
+
if (!feeRecord) {
|
|
6370
|
+
console.log("Private fee specified, but no private fee record provided, estimating fee and finding a matching fee record.");
|
|
6371
|
+
const programString = programObject.toString();
|
|
6372
|
+
const imports = await this.networkClient.getProgramImports(programString);
|
|
6373
|
+
const baseFee = Number(ProgramManager$1.estimateDeploymentFee(programString, imports));
|
|
6374
|
+
fee = baseFee + priorityFee;
|
|
6375
|
+
}
|
|
6376
|
+
// Get a credits.aleo record for the fee.
|
|
6377
|
+
feeRecord = await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams);
|
|
6378
|
+
}
|
|
6379
|
+
else {
|
|
6380
|
+
// If it's specified NOT to use a privateFee, use a public fee.
|
|
6381
|
+
feeRecord = undefined;
|
|
6382
|
+
}
|
|
6383
|
+
}
|
|
6384
|
+
catch (e) {
|
|
6385
|
+
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.`);
|
|
6386
|
+
}
|
|
6387
|
+
// Resolve the program imports if they exist.
|
|
6388
|
+
const numberOfImports = programObject.getImports().length;
|
|
6389
|
+
if (numberOfImports > 0 && !imports) {
|
|
6390
|
+
try {
|
|
6391
|
+
imports = (await this.networkClient.getProgramImports(programName));
|
|
6392
|
+
}
|
|
6393
|
+
catch (e) {
|
|
6394
|
+
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.`);
|
|
6395
|
+
}
|
|
6396
|
+
}
|
|
6397
|
+
// Build a transaction without a proof
|
|
6398
|
+
return await ProgramManager$1.buildDevnodeExecutionTransaction(executionPrivateKey, program, functionName, inputs, priorityFee, feeRecord, this.host, imports, edition);
|
|
6399
|
+
}
|
|
6400
|
+
/**
|
|
6401
|
+
* Builds a deployment transaction with placeholder certificates and verifying keys for each function in the program.
|
|
6402
|
+
* Intended for use with a local devnode.
|
|
6403
|
+
* `getOrInitConsensusVersionTestHeights` must be called with development heights prior to invoking this method for it to work properly.
|
|
6404
|
+
*
|
|
6405
|
+
* @param {DeployOptions} options - The options for the deployment transaction.
|
|
6406
|
+
* @returns {string} The transaction id of the deployed program or a failure message from the network
|
|
6407
|
+
*
|
|
6408
|
+
* @example
|
|
6409
|
+
* /// Import the mainnet version of the sdk.
|
|
6410
|
+
* import { ProgramManager, NetworkRecordProvider, getOrInitConsensusVersionTestHeights } from "@provablehq/sdk/mainnet.js";
|
|
6411
|
+
*
|
|
6412
|
+
* // Initialize the development consensus heights in order to work with a local devnode.
|
|
6413
|
+
* getOrInitConsensusVersionTestHeights("0,1,2,3,4,5,6,7,8,9,10,11");
|
|
6414
|
+
*
|
|
6415
|
+
* // Create a new NetworkClient, and RecordProvider
|
|
6416
|
+
* const recordProvider = new NetworkRecordProvider(account, networkClient);
|
|
6417
|
+
* keyProvider.useCache(true);
|
|
6418
|
+
*
|
|
6419
|
+
* // Initialize a program manager with the key provider to automatically fetch keys for deployments
|
|
6420
|
+
* const program = "program hello_hello.aleo;\n\nfunction hello:\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";
|
|
6421
|
+
* const programManager = new ProgramManager("http://localhost:3030", recordProvider);
|
|
6422
|
+
* programManager.setAccount(Account);
|
|
6423
|
+
*
|
|
6424
|
+
* // Define a fee in credits
|
|
6425
|
+
* const priorityFee = 0.0;
|
|
6426
|
+
*
|
|
6427
|
+
* // Create the deployment transaction.
|
|
6428
|
+
* const tx = await programManager.buildDevnodeDeploymentTransaction({program: program, fee: priorityFee, privateFee: false});
|
|
6429
|
+
* await programManager.networkClient.submitTransaction(tx);
|
|
6430
|
+
*
|
|
6431
|
+
* // Verify the transaction was successful
|
|
6432
|
+
* setTimeout(async () => {
|
|
6433
|
+
* const transaction = await programManager.networkClient.getTransaction(tx.id());
|
|
6434
|
+
* assert(transaction.id() === tx.id());
|
|
6435
|
+
* }, 20000);
|
|
6436
|
+
*/
|
|
6437
|
+
async buildDevnodeDeploymentTransaction(options) {
|
|
6438
|
+
const { program, priorityFee, privateFee, recordSearchParams } = options;
|
|
6439
|
+
let feeRecord = options.feeRecord;
|
|
6440
|
+
let privateKey = options.privateKey;
|
|
6441
|
+
// Ensure the program is valid.
|
|
6442
|
+
let programObject;
|
|
6443
|
+
try {
|
|
6444
|
+
programObject = Program.fromString(program);
|
|
6445
|
+
}
|
|
6446
|
+
catch (e) {
|
|
6447
|
+
logAndThrow(`Error parsing program: '${e.message}'. Please ensure the program is valid.`);
|
|
6448
|
+
}
|
|
6449
|
+
// Ensure the program is valid and does not exist on the network
|
|
6450
|
+
try {
|
|
6451
|
+
let programSource;
|
|
6452
|
+
try {
|
|
6453
|
+
programSource = await this.networkClient.getProgram(programObject.id());
|
|
6454
|
+
}
|
|
6455
|
+
catch (e) {
|
|
6456
|
+
// Program does not exist on the network, deployment can proceed
|
|
6457
|
+
console.log(`Program ${programObject.id()} does not exist on the network, deploying...`);
|
|
6458
|
+
}
|
|
6459
|
+
if (typeof programSource === "string") {
|
|
6460
|
+
throw Error(`Program ${programObject.id()} already exists on the network, please rename your program`);
|
|
6461
|
+
}
|
|
6462
|
+
}
|
|
6463
|
+
catch (e) {
|
|
6464
|
+
logAndThrow(`Error validating program: ${e.message}`);
|
|
6465
|
+
}
|
|
6466
|
+
// Get the private key from the account if it is not provided in the parameters
|
|
6467
|
+
let deploymentPrivateKey = privateKey;
|
|
6468
|
+
if (typeof privateKey === "undefined" &&
|
|
6469
|
+
typeof this.account !== "undefined") {
|
|
6470
|
+
deploymentPrivateKey = this.account.privateKey();
|
|
6471
|
+
}
|
|
6472
|
+
if (typeof deploymentPrivateKey === "undefined") {
|
|
6473
|
+
throw "No private key provided and no private key set in the ProgramManager";
|
|
6474
|
+
}
|
|
6475
|
+
// Get the fee record from the account if it is not provided in the parameters
|
|
6476
|
+
try {
|
|
6477
|
+
if (privateFee) {
|
|
6478
|
+
let fee = priorityFee;
|
|
6479
|
+
// If a private fee is specified, but no fee record is provided, estimate the fee and find a matching record.
|
|
6480
|
+
if (!feeRecord) {
|
|
6481
|
+
console.log("Private fee specified, but no private fee record provided, estimating fee and finding a matching fee record.");
|
|
6482
|
+
const programString = programObject.toString();
|
|
6483
|
+
const imports = await this.networkClient.getProgramImports(programString);
|
|
6484
|
+
const baseFee = Number(ProgramManager$1.estimateDeploymentFee(programString, imports));
|
|
6485
|
+
fee = baseFee + priorityFee;
|
|
6486
|
+
}
|
|
6487
|
+
// Get a credits.aleo record for the fee.
|
|
6488
|
+
feeRecord = await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams);
|
|
6489
|
+
}
|
|
6490
|
+
else {
|
|
6491
|
+
// If it's specified NOT to use a privateFee, use a public fee.
|
|
6492
|
+
feeRecord = undefined;
|
|
6493
|
+
}
|
|
6494
|
+
}
|
|
6495
|
+
catch (e) {
|
|
6496
|
+
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.`);
|
|
6497
|
+
}
|
|
6498
|
+
// Resolve the program imports if they exist
|
|
6499
|
+
let imports;
|
|
6500
|
+
try {
|
|
6501
|
+
imports = await this.networkClient.getProgramImports(program);
|
|
6502
|
+
}
|
|
6503
|
+
catch (e) {
|
|
6504
|
+
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.`);
|
|
6505
|
+
}
|
|
6506
|
+
return await ProgramManager$1.buildDevnodeDeploymentTransaction(deploymentPrivateKey, program, priorityFee, feeRecord, this.host, imports);
|
|
6507
|
+
}
|
|
6508
|
+
/**
|
|
6509
|
+
* Builds an upgrade transaction on a local devnodewith placeholder certificates and verifying keys for each function in the program.
|
|
6510
|
+
* This method is only intended for use with a local devnode.
|
|
6511
|
+
*
|
|
6512
|
+
* @param {DeployOptions} options - The options for the deployment transaction.
|
|
6513
|
+
* @returns {string} The transaction id of the deployed program or a failure message from the network
|
|
6514
|
+
*
|
|
6515
|
+
* @example
|
|
6516
|
+
* /// Import the mainnet version of the sdk.
|
|
6517
|
+
* import { ProgramManager, NetworkRecordProvider } from "@provablehq/sdk/mainnet.js";
|
|
6518
|
+
*
|
|
6519
|
+
* // Create a new NetworkClient, and RecordProvider
|
|
6520
|
+
* const recordProvider = new NetworkRecordProvider(account, networkClient);
|
|
6521
|
+
* keyProvider.useCache(true);
|
|
6522
|
+
*
|
|
6523
|
+
* // Initialize a program manager with the key provider to automatically fetch keys for deployments
|
|
6524
|
+
* const program = "program hello_hello.aleo;\n\nfunction hello:\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";
|
|
6525
|
+
* const programManager = new ProgramManager("http://localhost:3030", recordProvider);
|
|
6526
|
+
* programManager.setAccount(Account);
|
|
6527
|
+
*
|
|
6528
|
+
* // Define a fee in credits
|
|
6529
|
+
* const priorityFee = 0.0;
|
|
6530
|
+
*
|
|
6531
|
+
* // Create the deployment transaction.
|
|
6532
|
+
* const tx = await programManager.buildDevnodeUpgradeTransaction({program: program, fee: priorityFee, privateFee: false});
|
|
6533
|
+
* await programManager.networkClient.submitTransaction(tx);
|
|
6534
|
+
*
|
|
6535
|
+
* // Verify the transaction was successful
|
|
6536
|
+
* setTimeout(async () => {
|
|
6537
|
+
* const transaction = await programManager.networkClient.getTransaction(tx.id());
|
|
6538
|
+
* assert(transaction.id() === tx.id());
|
|
6539
|
+
* }, 20000);
|
|
6540
|
+
*/
|
|
6541
|
+
async buildDevnodeUpgradeTransaction(options) {
|
|
6542
|
+
const { program, priorityFee, privateFee, recordSearchParams } = options;
|
|
6543
|
+
let feeRecord = options.feeRecord;
|
|
6544
|
+
let privateKey = options.privateKey;
|
|
6545
|
+
// Ensure the program is valid.
|
|
6546
|
+
let programObject;
|
|
6547
|
+
try {
|
|
6548
|
+
programObject = Program.fromString(program);
|
|
6549
|
+
}
|
|
6550
|
+
catch (e) {
|
|
6551
|
+
logAndThrow(`Error parsing program: '${e.message}'. Please ensure the program is valid.`);
|
|
6552
|
+
}
|
|
6553
|
+
// Ensure the program is valid and does not exist on the network.
|
|
6554
|
+
try {
|
|
6555
|
+
let programSource;
|
|
6556
|
+
try {
|
|
6557
|
+
programSource = await this.networkClient.getProgram(programObject.id());
|
|
6558
|
+
}
|
|
6559
|
+
catch (e) {
|
|
6560
|
+
// Program does not exist on the network.
|
|
6561
|
+
logAndThrow(`Program ${programObject.id()} does not exist on the network...`);
|
|
6562
|
+
}
|
|
6563
|
+
}
|
|
6564
|
+
catch (e) {
|
|
6565
|
+
logAndThrow(`Error validating program: ${e.message}`);
|
|
6566
|
+
}
|
|
6567
|
+
// Get the private key from the account if it is not provided in the parameters
|
|
6568
|
+
let deploymentPrivateKey = privateKey;
|
|
6569
|
+
if (typeof privateKey === "undefined" &&
|
|
6570
|
+
typeof this.account !== "undefined") {
|
|
6571
|
+
deploymentPrivateKey = this.account.privateKey();
|
|
6572
|
+
}
|
|
6573
|
+
if (typeof deploymentPrivateKey === "undefined") {
|
|
6574
|
+
throw "No private key provided and no private key set in the ProgramManager";
|
|
6575
|
+
}
|
|
6576
|
+
// Get the fee record from the account if it is not provided in the parameters
|
|
6577
|
+
try {
|
|
6578
|
+
if (privateFee) {
|
|
6579
|
+
let fee = priorityFee;
|
|
6580
|
+
// If a private fee is specified, but no fee record is provided, estimate the fee and find a matching record.
|
|
6581
|
+
if (!feeRecord) {
|
|
6582
|
+
console.log("Private fee specified, but no private fee record provided, estimating fee and finding a matching fee record.");
|
|
6583
|
+
const programString = programObject.toString();
|
|
6584
|
+
const imports = await this.networkClient.getProgramImports(programString);
|
|
6585
|
+
const baseFee = Number(ProgramManager$1.estimateDeploymentFee(programString, imports));
|
|
6586
|
+
fee = baseFee + priorityFee;
|
|
6587
|
+
}
|
|
6588
|
+
// Get a credits.aleo record for the fee.
|
|
6589
|
+
feeRecord = await this.getCreditsRecord(fee, [], feeRecord, recordSearchParams);
|
|
6590
|
+
}
|
|
6591
|
+
else {
|
|
6592
|
+
// If it's specified NOT to use a privateFee, use a public fee.
|
|
6593
|
+
feeRecord = undefined;
|
|
6594
|
+
}
|
|
6595
|
+
}
|
|
6596
|
+
catch (e) {
|
|
6597
|
+
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.`);
|
|
6598
|
+
}
|
|
6599
|
+
// Resolve the program imports if they exist
|
|
6600
|
+
let imports;
|
|
6601
|
+
try {
|
|
6602
|
+
imports = await this.networkClient.getProgramImports(program);
|
|
6603
|
+
}
|
|
6604
|
+
catch (e) {
|
|
6605
|
+
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.`);
|
|
6606
|
+
}
|
|
6607
|
+
return ProgramManager$1.buildDevnodeUpgradeTransaction(deploymentPrivateKey, program, priorityFee, feeRecord, this.host, imports);
|
|
6608
|
+
}
|
|
6008
6609
|
}
|
|
6009
6610
|
// Ensure the transfer type requires an amount record
|
|
6010
6611
|
function requiresAmountRecord(transferType) {
|