@fairblock/stabletrust 1.0.11 → 1.0.13

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/client.js +36 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fairblock/stabletrust",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "SDK for confidential transfers using homomorphic encryption and zero-knowledge proofs",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
package/src/client.js CHANGED
@@ -74,6 +74,9 @@ export class ConfidentialTransferClient {
74
74
  // WASM will be auto-initialized on first use
75
75
  this._wasmModule = null;
76
76
 
77
+ // Cache for derived keys — deterministic per wallet+chain+contract, safe to reuse
78
+ this._keyCache = new Map();
79
+
77
80
  try {
78
81
  this.provider = new ethers.JsonRpcProvider(this.config.rpcUrl);
79
82
  this.contract = new ethers.Contract(
@@ -118,8 +121,12 @@ export class ConfidentialTransferClient {
118
121
  if (!wallet) {
119
122
  throw new Error("Wallet is required");
120
123
  }
124
+ const address = await wallet.getAddress();
125
+ if (this._keyCache.has(address)) {
126
+ return this._keyCache.get(address);
127
+ }
121
128
  const wasm = await this._getWasm();
122
- return await deriveKeys(
129
+ const keys = await deriveKeys(
123
130
  wallet,
124
131
  {
125
132
  chainId: this.config.chainId,
@@ -127,6 +134,8 @@ export class ConfidentialTransferClient {
127
134
  },
128
135
  wasm.generate_deterministic_keypair,
129
136
  );
137
+ this._keyCache.set(address, keys);
138
+ return keys;
130
139
  } catch (error) {
131
140
  throw new Error(`Failed to derive keys: ${error.message}`);
132
141
  }
@@ -155,11 +164,11 @@ export class ConfidentialTransferClient {
155
164
  * @param {ethers.Wallet|ethers.Signer} wallet - The wallet to create account for
156
165
  * @param {Object} [options] - Options
157
166
  * @param {boolean} [options.waitForFinalization=true] - Wait for account finalization
158
- * @param {number} [options.maxAttempts=30] - Max attempts to wait for finalization
167
+ * @param {number} [options.maxAttempts=225] - Max attempts to wait for finalization
159
168
  * @returns {Promise<{publicKey: string, privateKey: string}>} The derived keys
160
169
  */
161
170
  async ensureAccount(wallet, options = {}) {
162
- const { waitForFinalization = true, maxAttempts = 30 } = options;
171
+ const { waitForFinalization = true, maxAttempts = 225 } = options;
163
172
 
164
173
  try {
165
174
  const address = await wallet.getAddress();
@@ -183,7 +192,7 @@ export class ConfidentialTransferClient {
183
192
  if (waitForFinalization) {
184
193
  let attempts = 0;
185
194
  while (!accountInfo.finalized && attempts < maxAttempts) {
186
- await sleep(2000);
195
+ await sleep(400);
187
196
  accountInfo = await this.getAccountInfo(address);
188
197
  attempts++;
189
198
  }
@@ -354,20 +363,17 @@ export class ConfidentialTransferClient {
354
363
  const depositAmount = BigInt(amount);
355
364
  const tokenContract = this._getTokenContract(tokenAddress);
356
365
 
357
- // Check token balance
358
- const tokenBalance = await tokenContract.balanceOf(address);
366
+ // Check token balance and allowance in parallel
367
+ const [tokenBalance, allowance] = await Promise.all([
368
+ tokenContract.balanceOf(address),
369
+ tokenContract.allowance(address, this.config.contractAddress),
370
+ ]);
359
371
  if (tokenBalance < depositAmount) {
360
372
  throw new Error(
361
373
  `Insufficient token balance. Required: ${depositAmount}, Available: ${tokenBalance}`,
362
374
  );
363
375
  }
364
376
 
365
- // Check and approve if needed
366
- const allowance = await tokenContract.allowance(
367
- address,
368
- this.config.contractAddress,
369
- );
370
-
371
377
  if (allowance < depositAmount) {
372
378
  const approveTx = await tokenContract
373
379
  .connect(wallet)
@@ -439,14 +445,15 @@ export class ConfidentialTransferClient {
439
445
 
440
446
  const senderAddress = await senderWallet.getAddress();
441
447
 
442
- // Auto-derive sender keys
443
- const derivedSenderKeys = await this._deriveKeys(senderWallet);
448
+ // Derive sender keys and fetch recipient account info in parallel
449
+ const [derivedSenderKeys, recipientAccountInfo] = await Promise.all([
450
+ this._deriveKeys(senderWallet),
451
+ this.getAccountInfo(recipientAddress),
452
+ ]);
444
453
  if (!derivedSenderKeys?.privateKey) {
445
454
  throw new Error("Failed to derive sender keys");
446
455
  }
447
456
 
448
- // Auto-derive recipient public key
449
- const recipientAccountInfo = await this.getAccountInfo(recipientAddress);
450
457
  if (!recipientAccountInfo.exists) {
451
458
  throw new Error(
452
459
  `Recipient account does not exist. Address: ${recipientAddress}`,
@@ -474,12 +481,14 @@ export class ConfidentialTransferClient {
474
481
  "transfer",
475
482
  );
476
483
 
477
- const balanceSummary = await this.getConfidentialBalance(
478
- senderAddress,
479
- derivedSenderKeys.privateKey,
480
- tokenAddress,
481
- );
482
- const fee = await this.getFeeAmount();
484
+ const [balanceSummary, fee] = await Promise.all([
485
+ this.getConfidentialBalance(
486
+ senderAddress,
487
+ derivedSenderKeys.privateKey,
488
+ tokenAddress,
489
+ ),
490
+ this.getFeeAmount(),
491
+ ]);
483
492
  const derivedCurrentBalanceCiphertext =
484
493
  balanceSummary.available.ciphertext;
485
494
  const derivedCurrentBalance = balanceSummary.available.amount;
@@ -881,7 +890,8 @@ export class ConfidentialTransferClient {
881
890
  */
882
891
  async _waitForGlobalState(address, actionLabel) {
883
892
  let attempts = 0;
884
- const maxAttempts = 300;
893
+ const maxAttempts = 450; // 450 * 200ms = 90 seconds max wait
894
+ await sleep(2000);
885
895
 
886
896
  while (attempts < maxAttempts) {
887
897
  try {
@@ -912,8 +922,8 @@ export class ConfidentialTransferClient {
912
922
  * @param {string} privateKey - Private key for decryption
913
923
  * @param {string} tokenAddress - Token address
914
924
  * @param {Object} [options] - Options
915
- * @param {number} [options.maxAttempts=60] - Maximum polling attempts
916
- * @param {number} [options.intervalMs=3000] - Polling interval in milliseconds
925
+ * @param {number} [options.maxAttempts=225] - Maximum polling attempts
926
+ * @param {number} [options.intervalMs=400] - Polling interval in milliseconds
917
927
  * @returns {Promise<{amount: number, ciphertext: string}>}
918
928
  */
919
929
  async _waitForPendingBalance(
@@ -922,7 +932,7 @@ export class ConfidentialTransferClient {
922
932
  tokenAddress,
923
933
  options = {},
924
934
  ) {
925
- const { maxAttempts = 60, intervalMs = 3000 } = options;
935
+ const { maxAttempts = 225, intervalMs = 400 } = options;
926
936
 
927
937
  try {
928
938
  for (let i = 0; i < maxAttempts; i++) {