@fairblock/stabletrust 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,20 @@
1
1
  /**
2
2
  * Anonymous Confidential Transfer — Basic Flow
3
3
  *
4
- * [1] Create two anonymous accounts (anon1, anon2)
5
- * [2] Deposit tokens into anon1
6
- * [3] Transfer anon1 → anon2
7
- * [4] Apply pending balance for anon2
8
- * [5] Withdraw anon2 → public address
4
+ * [1] Generate two UUIDs as account IDs
5
+ * [2] Derive ElGamal keypairs for both accounts
6
+ * [3] Create both anonymous accounts via Fairycloak
7
+ * [4] Deposit tokens into anon1
8
+ * [5] Transfer anon1 → anon2
9
+ * [6] Apply pending balance for anon2
10
+ * [7] Withdraw anon2 → public address
9
11
  *
10
12
  * Run:
11
13
  * node examples/anonymous-flow.js
12
14
  */
13
15
 
14
16
  import { ethers } from "ethers";
17
+ import { randomUUID } from "crypto";
15
18
  import dotenv from "dotenv";
16
19
  import { AnonymousTransferClient } from "@fairblock/stabletrust";
17
20
 
@@ -64,14 +67,6 @@ async function logBalance(client, accountId, keys, token, _decimals, label) {
64
67
  return bal;
65
68
  }
66
69
 
67
- function diff(prev, next) {
68
- return {
69
- avail: next.available - prev.available,
70
- pending: next.pending - prev.pending,
71
- total: next.amount - prev.amount,
72
- };
73
- }
74
-
75
70
  /**
76
71
  * Poll until hasPendingAction flips to false (CW→EVM state settled).
77
72
  */
@@ -122,17 +117,20 @@ async function main() {
122
117
  rpcUrl: EVM_RPC,
123
118
  });
124
119
 
125
- // ── [1] Create accounts ──────────────────────────────────────────────────────
120
+ // ── [1] Generate account IDs ─────────────────────────────────────────────────
121
+
122
+ console.log("\n── [1] Generate anonymous account IDs ──────────────────");
126
123
 
127
- console.log("\n── [1] Create anonymous accounts ───────────────────────");
124
+ const anon1Id = randomUUID();
125
+ const anon2Id = randomUUID();
126
+ log("anon1 id:", anon1Id);
127
+ log("anon2 id:", anon2Id);
128
128
 
129
- const nextId = await client.getNextAccountId();
130
- const anon1Id = Number(nextId) + 1;
131
- const anon2Id = anon1Id + 1;
132
- log("anon1 id will be:", anon1Id);
133
- log("anon2 id will be:", anon2Id);
129
+ // ── [2] Derive ElGamal keypairs ──────────────────────────────────────────────
130
+
131
+ console.log("\n── [2] Derive ElGamal keypairs ─────────────────────────");
132
+ log("Deriving ElGamal keypairs from wallets + account IDs …");
134
133
 
135
- log("Deriving ElGamal keypairs …");
136
134
  const [anon1Keys, anon2Keys] = await Promise.all([
137
135
  client.deriveAnonymousKeys(anon1Wallet, anon1Id),
138
136
  client.deriveAnonymousKeys(anon2Wallet, anon2Id),
@@ -140,13 +138,17 @@ async function main() {
140
138
  log("anon1 pubkey:", anon1Keys.publicKey);
141
139
  log("anon2 pubkey:", anon2Keys.publicKey);
142
140
 
141
+ // ── [3] Create accounts ──────────────────────────────────────────────────────
142
+
143
+ console.log("\n── [3] Create anonymous accounts ───────────────────────");
144
+
143
145
  log(` creating anon1 (id=${anon1Id}) …`);
144
- const cr1 = await client.createAccount(anon1Wallet, anon1Keys.publicKey);
146
+ const cr1 = await client.createAccount(anon1Wallet, anon1Id, anon1Keys.publicKey);
145
147
  log(` request_id: ${cr1.request_id} status: ${cr1.status}`);
146
148
  if (cr1.error) log(` [!] Error: ${cr1.error}`);
147
149
 
148
150
  log(` creating anon2 (id=${anon2Id}) …`);
149
- const cr2 = await client.createAccount(anon2Wallet, anon2Keys.publicKey);
151
+ const cr2 = await client.createAccount(anon2Wallet, anon2Id, anon2Keys.publicKey);
150
152
  log(` request_id: ${cr2.request_id} status: ${cr2.status}`);
151
153
  if (cr2.error) log(` [!] Error: ${cr2.error}`);
152
154
 
@@ -185,9 +187,9 @@ async function main() {
185
187
  "anon2:post-create",
186
188
  );
187
189
 
188
- // ── [2] Deposit ──────────────────────────────────────────────────────────────
190
+ // ── [4] Deposit ──────────────────────────────────────────────────────────────
189
191
 
190
- console.log("\n── [2] Deposit into anon1 ──────────────────────────────");
192
+ console.log("\n── [4] Deposit into anon1 ──────────────────────────────");
191
193
  log(`Depositing ${fmt(DEPOSIT_AMOUNT, TOKEN_DECIMALS)} tokens into anon1 (anon1 pays gas) …`);
192
194
 
193
195
  const dep = await client.deposit(
@@ -216,9 +218,9 @@ async function main() {
216
218
  "anon1:post-deposit",
217
219
  );
218
220
 
219
- // ── [3] Transfer anon1 → anon2 ───────────────────────────────────────────────
221
+ // ── [5] Transfer anon1 → anon2 ───────────────────────────────────────────────
220
222
 
221
- console.log("\n── [3] Transfer anon1 → anon2 ──────────────────────────");
223
+ console.log("\n── [5] Transfer anon1 → anon2 ──────────────────────────");
222
224
  log(`Transferring ${fmt(TRANSFER_AMOUNT, TOKEN_DECIMALS)} tokens …`);
223
225
 
224
226
  const txAnon = await client.transferToAnonymous(anon1Wallet, anon1Id, {
@@ -261,9 +263,9 @@ async function main() {
261
263
  "anon2:post-transfer",
262
264
  );
263
265
 
264
- // ── [4] Apply pending for anon2 ──────────────────────────────────────────────
266
+ // ── [6] Apply pending for anon2 ──────────────────────────────────────────────
265
267
 
266
- console.log("\n── [4] Apply pending balance for anon2 ─────────────────");
268
+ console.log("\n── [6] Apply pending balance for anon2 ─────────────────");
267
269
  log("Moving incoming credit from pending → available …");
268
270
 
269
271
  const ap = await client.applyPending(anon2Wallet, anon2Id);
@@ -287,9 +289,9 @@ async function main() {
287
289
  "anon2:post-apply",
288
290
  );
289
291
 
290
- // ── [5] Withdraw anon2 → public address ──────────────────────────────────────
292
+ // ── [7] Withdraw anon2 → public address ──────────────────────────────────────
291
293
 
292
- console.log("\n── [5] Withdraw from anon2 ─────────────────────────────");
294
+ console.log("\n── [7] Withdraw from anon2 ─────────────────────────────");
293
295
  log(`Withdrawing ${fmt(WITHDRAW_AMOUNT, TOKEN_DECIMALS)} tokens → ${withdrawDest} …`);
294
296
 
295
297
  const wd = await client.withdraw(anon2Wallet, anon2Id, {
@@ -323,6 +325,8 @@ async function main() {
323
325
  console.log("\n═══════════════════════════════════════════════════════");
324
326
  console.log(" ✅ Anonymous flow completed!");
325
327
  console.log("═══════════════════════════════════════════════════════");
328
+ log("anon1 id :", anon1Id);
329
+ log("anon2 id :", anon2Id);
326
330
  log("Deposited :", ethers.formatUnits(DEPOSIT_AMOUNT, TOKEN_DECIMALS), "tokens → anon1");
327
331
  log("Transferred:", ethers.formatUnits(TRANSFER_AMOUNT, TOKEN_DECIMALS), "tokens → anon2");
328
332
  log("Withdrawn :", ethers.formatUnits(WITHDRAW_AMOUNT, TOKEN_DECIMALS), "tokens →", withdrawDest);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fairblock/stabletrust",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
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",
@@ -12,7 +12,7 @@ const DEFAULT_DEADLINE_OFFSET = 3600;
12
12
 
13
13
  // Minimal ABI — only used for deposit calldata encoding (reads go through Fairycloak views)
14
14
  const DEPOSIT_INTERFACE = new ethers.Interface([
15
- "function depositAnonymous(uint64 accountId, address token, uint256 plainAmount, uint256 authNonce, uint256 deadline, bytes authSig) external",
15
+ "function depositAnonymous(string accountId, address token, uint256 plainAmount, uint256 authNonce, uint256 deadline, bytes authSig) external",
16
16
  ]);
17
17
 
18
18
  /**
@@ -184,7 +184,7 @@ export class AnonymousTransferClient {
184
184
  /**
185
185
  * Get on-chain core state for an anonymous account.
186
186
  *
187
- * @param {number|bigint} accountId
187
+ * @param {string} accountId
188
188
  * @returns {Promise<{exists:boolean, finalized:boolean, hasPendingAction:boolean, txId:bigint, elgamalPubkey:string, authNonce:bigint}>}
189
189
  */
190
190
  async getAnonymousAccountInfo(accountId) {
@@ -215,7 +215,7 @@ export class AnonymousTransferClient {
215
215
  /**
216
216
  * Read the current authNonce for an anonymous account from the chain.
217
217
  *
218
- * @param {number|bigint} accountId
218
+ * @param {string} accountId
219
219
  * @returns {Promise<bigint>}
220
220
  */
221
221
  async getAuthNonce(accountId) {
@@ -223,32 +223,10 @@ export class AnonymousTransferClient {
223
223
  return info.authNonce;
224
224
  }
225
225
 
226
- /**
227
- * Read the current anonymous account count from the contract.
228
- *
229
- * The contract assigns IDs starting at 1 and incrementing sequentially.
230
- * The ID of the *next* account to be created is therefore `count + 1`.
231
- *
232
- * ```js
233
- * const count = await client.getNextAccountId();
234
- * const myId = Number(count) + 1; // ID that will be assigned
235
- * await client.createAccount(wallet, pubkey);
236
- * ```
237
- *
238
- * @returns {Promise<bigint>} Current account count (not the next ID)
239
- */
240
- async getNextAccountId() {
241
- const data = await this._fetch(
242
- "GET",
243
- "/v1/views/anonymous/next-account-id",
244
- );
245
- return BigInt(data.result);
246
- }
247
-
248
226
  /**
249
227
  * Check whether an address is an authorised signer for an anonymous account.
250
228
  *
251
- * @param {number|bigint} accountId
229
+ * @param {string} accountId
252
230
  * @param {string} signerAddress
253
231
  * @returns {Promise<boolean>}
254
232
  */
@@ -266,7 +244,7 @@ export class AnonymousTransferClient {
266
244
  * Fetch the raw combined ciphertext (base64) for an anonymous account's balance.
267
245
  * Returns null when no balance has been set yet.
268
246
  *
269
- * @param {number|bigint} accountId
247
+ * @param {string} accountId
270
248
  * @param {string} tokenAddress
271
249
  * @param {"available"|"pending"} [type="available"]
272
250
  * @returns {Promise<string|null>} Base64 ciphertext or null
@@ -293,7 +271,7 @@ export class AnonymousTransferClient {
293
271
  * Decrypt an anonymous account's balance from the chain.
294
272
  * Returns amount in **contract scale** (the raw WASM-decrypted value).
295
273
  *
296
- * @param {number|bigint} accountId
274
+ * @param {string} accountId
297
275
  * @param {string} tokenAddress
298
276
  * @param {string} elGamalPrivateKey - Base64 private key
299
277
  * @param {"available"|"pending"} [type="available"]
@@ -325,7 +303,7 @@ export class AnonymousTransferClient {
325
303
  * Amounts are returned in **contract scale** (the encrypted integer stored on-chain,
326
304
  * equivalent to `tokenAmount × 100 / 10^decimals`).
327
305
  *
328
- * @param {number|bigint} accountId
306
+ * @param {string} accountId
329
307
  * @param {string} tokenAddress - ERC-20 token address
330
308
  * @param {string} elGamalPrivateKey - ElGamal private key (base64) for decryption
331
309
  * @returns {Promise<{available: {amount: number, ciphertext: string|null}, pending: {amount: number, ciphertext: string|null}}>}
@@ -362,7 +340,7 @@ export class AnonymousTransferClient {
362
340
  * Store the returned `privateKey` securely — it cannot be recovered without the wallet.
363
341
  *
364
342
  * @param {ethers.Wallet|ethers.Signer} authWallet
365
- * @param {number|bigint} accountId
343
+ * @param {string} accountId
366
344
  * @returns {Promise<{publicKey:string, privateKey:string}>} Base-64 encoded keypair
367
345
  */
368
346
  async deriveAnonymousKeys(authWallet, accountId) {
@@ -379,25 +357,25 @@ export class AnonymousTransferClient {
379
357
  const types = {
380
358
  DeriveAnonymousElGamalKey: [
381
359
  { name: "purpose", type: "string" },
382
- { name: "accountId", type: "uint256" },
360
+ { name: "accountId", type: "string" },
383
361
  { name: "user", type: "address" },
384
362
  { name: "context", type: "bytes32" },
385
363
  ],
386
364
  };
387
365
  const contextHash = ethers.keccak256(
388
366
  ethers.AbiCoder.defaultAbiCoder().encode(
389
- ["uint256", "address", "uint256", "string"],
367
+ ["uint256", "address", "string", "string"],
390
368
  [
391
369
  this.chainId,
392
370
  this.diamondAddress,
393
- BigInt(accountId),
371
+ String(accountId),
394
372
  "anonymous-main",
395
373
  ],
396
374
  ),
397
375
  );
398
376
  const message = {
399
377
  purpose: "anonymous-elgamal-key-derive-v1",
400
- accountId: BigInt(accountId),
378
+ accountId: String(accountId),
401
379
  user: address.toLowerCase(),
402
380
  context: contextHash,
403
381
  };
@@ -527,12 +505,13 @@ export class AnonymousTransferClient {
527
505
  * The relay submits the `createAnonymousAccount` transaction and pays gas.
528
506
  *
529
507
  * @param {ethers.Wallet|ethers.Signer} authWallet - Initial auth signer
508
+ * @param {string} accountId - Caller-chosen account ID (non-empty string, case-sensitive)
530
509
  * @param {string} elgamalPublicKey - ElGamal public key as base64 or "0x"-prefixed hex (32 bytes)
531
510
  * @param {Object} [options]
532
511
  * @param {number} [options.deadlineOffset=3600] - Deadline in seconds from now
533
512
  * @returns {Promise<{request_id:string, tx_hash:string, status:string, action:string}>}
534
513
  */
535
- async createAccount(authWallet, elgamalPublicKey, options = {}) {
514
+ async createAccount(authWallet, accountId, elgamalPublicKey, options = {}) {
536
515
  const { deadlineOffset = DEFAULT_DEADLINE_OFFSET } = options;
537
516
  try {
538
517
  const authAddress = await authWallet.getAddress();
@@ -558,6 +537,7 @@ export class AnonymousTransferClient {
558
537
  const domain = this._buildDomain();
559
538
  const types = {
560
539
  AnonymousCreate: [
540
+ { name: "accountId", type: "string" },
561
541
  { name: "initialSignersHash", type: "bytes32" },
562
542
  { name: "elgamalPubkeyHash", type: "bytes32" },
563
543
  { name: "clientRequestId", type: "bytes32" },
@@ -565,6 +545,7 @@ export class AnonymousTransferClient {
565
545
  ],
566
546
  };
567
547
  const value = {
548
+ accountId,
568
549
  initialSignersHash,
569
550
  elgamalPubkeyHash,
570
551
  clientRequestId,
@@ -574,6 +555,7 @@ export class AnonymousTransferClient {
574
555
  const signature = await authWallet.signTypedData(domain, types, value);
575
556
 
576
557
  return await this._fetch("POST", "/v1/anonymous/accounts", {
558
+ account_id: accountId,
577
559
  elgamal_pubkey: elgamalHex,
578
560
  auth_pubkeys: [authPubkey],
579
561
  client_request_id: clientRequestId,
@@ -591,7 +573,7 @@ export class AnonymousTransferClient {
591
573
  * Update the set of authorised signers for an anonymous account via Fairycloak.
592
574
  *
593
575
  * @param {ethers.Wallet|ethers.Signer} authWallet - A currently authorised signer
594
- * @param {number|bigint} accountId
576
+ * @param {string} accountId
595
577
  * @param {Object} keys
596
578
  * @param {Array<string|ethers.Wallet>} [keys.add=[]] - Pubkeys/wallets to add
597
579
  * @param {Array<string|ethers.Wallet>} [keys.remove=[]] - Pubkeys/wallets to remove
@@ -632,7 +614,7 @@ export class AnonymousTransferClient {
632
614
  const domain = this._buildDomain();
633
615
  const types = {
634
616
  AnonymousUpdateKeys: [
635
- { name: "accountId", type: "uint64" },
617
+ { name: "accountId", type: "string" },
636
618
  { name: "addSignersHash", type: "bytes32" },
637
619
  { name: "removeSignersHash", type: "bytes32" },
638
620
  { name: "authNonce", type: "uint256" },
@@ -640,7 +622,7 @@ export class AnonymousTransferClient {
640
622
  ],
641
623
  };
642
624
  const value = {
643
- accountId: BigInt(accountId),
625
+ accountId: String(accountId),
644
626
  addSignersHash,
645
627
  removeSignersHash,
646
628
  authNonce,
@@ -650,7 +632,7 @@ export class AnonymousTransferClient {
650
632
  const signature = await authWallet.signTypedData(domain, types, value);
651
633
 
652
634
  return await this._fetch("POST", "/v1/anonymous/keys/update", {
653
- account_id: Number(accountId),
635
+ account_id: accountId,
654
636
  add_pubkeys: addPubkeys,
655
637
  remove_pubkeys: removePubkeys,
656
638
  auth_nonce: String(authNonce),
@@ -677,7 +659,7 @@ export class AnonymousTransferClient {
677
659
  * 4. Submit to Fairycloak `/v1/anonymous/deposit/raw-tx`
678
660
  *
679
661
  * @param {ethers.Wallet} authWallet - Wallet that owns the tokens and signs the tx
680
- * @param {number|bigint} accountId - Target anonymous account ID
662
+ * @param {string} accountId - Target anonymous account ID
681
663
  * @param {string} tokenAddress - ERC-20 token address
682
664
  * @param {bigint|string|number} amount - Amount in token units (wei-scaled by token decimals)
683
665
  * @param {Object} [options]
@@ -751,7 +733,7 @@ export class AnonymousTransferClient {
751
733
  const domain = this._buildDomain();
752
734
  const types = {
753
735
  AnonymousDeposit: [
754
- { name: "accountId", type: "uint64" },
736
+ { name: "accountId", type: "string" },
755
737
  { name: "token", type: "address" },
756
738
  { name: "plainAmount", type: "uint256" },
757
739
  { name: "authNonce", type: "uint256" },
@@ -759,7 +741,7 @@ export class AnonymousTransferClient {
759
741
  ],
760
742
  };
761
743
  const value = {
762
- accountId: BigInt(accountId),
744
+ accountId: String(accountId),
763
745
  token: tokenAddress,
764
746
  plainAmount: plainAmountContractScale,
765
747
  authNonce,
@@ -772,7 +754,7 @@ export class AnonymousTransferClient {
772
754
  const calldata = DEPOSIT_INTERFACE.encodeFunctionData(
773
755
  "depositAnonymous",
774
756
  [
775
- BigInt(accountId),
757
+ accountId,
776
758
  tokenAddress,
777
759
  plainAmountContractScale,
778
760
  authNonce,
@@ -834,7 +816,7 @@ export class AnonymousTransferClient {
834
816
  * **Manual proof mode**: provide a pre-computed `proof` hex string from `generateTransferProof()`.
835
817
  *
836
818
  * @param {ethers.Wallet|ethers.Signer} authWallet - Authorised signer for the anonymous account
837
- * @param {number|bigint} accountId - Sender's anonymous account ID
819
+ * @param {string} accountId - Sender's anonymous account ID
838
820
  * @param {Object} params
839
821
  * @param {string} params.recipient - Recipient EVM address (must have a confidential account)
840
822
  * @param {string} params.token - Token address
@@ -892,7 +874,7 @@ export class AnonymousTransferClient {
892
874
  `Recipient ${recipient} has no confidential account on-chain`,
893
875
  );
894
876
  destPubkey = Buffer.from(
895
- ethers.getBytes(recipientData.result.pubkey),
877
+ ethers.getBytes(recipientData.result.elgamal_pubkey),
896
878
  ).toString("base64");
897
879
  }
898
880
 
@@ -923,7 +905,7 @@ export class AnonymousTransferClient {
923
905
  const domain = this._buildDomain();
924
906
  const types = {
925
907
  AnonymousTransferToPublic: [
926
- { name: "senderId", type: "uint64" },
908
+ { name: "senderId", type: "string" },
927
909
  { name: "recipient", type: "address" },
928
910
  { name: "token", type: "address" },
929
911
  { name: "proofHash", type: "bytes32" },
@@ -932,7 +914,7 @@ export class AnonymousTransferClient {
932
914
  ],
933
915
  };
934
916
  const value = {
935
- senderId: BigInt(accountId),
917
+ senderId: String(accountId),
936
918
  recipient,
937
919
  token,
938
920
  proofHash,
@@ -943,7 +925,7 @@ export class AnonymousTransferClient {
943
925
  const signature = await authWallet.signTypedData(domain, types, value);
944
926
 
945
927
  return await this._fetch("POST", "/v1/anonymous/transfers/public", {
946
- sender_id: Number(accountId),
928
+ sender_id: accountId,
947
929
  recipient,
948
930
  token,
949
931
  proof: proofHex,
@@ -968,9 +950,9 @@ export class AnonymousTransferClient {
968
950
  * **Manual proof mode**: provide a pre-computed `proof` hex string from `generateTransferProof()`.
969
951
  *
970
952
  * @param {ethers.Wallet|ethers.Signer} authWallet - Authorised signer for the sender account
971
- * @param {number|bigint} senderAccountId
953
+ * @param {string} senderAccountId
972
954
  * @param {Object} params
973
- * @param {number|bigint} params.recipientId - Recipient anonymous account ID
955
+ * @param {string} params.recipientId - Recipient anonymous account ID
974
956
  * @param {string} params.token - Token address
975
957
  * @param {string} [params.proof] - Pre-computed ZK proof ("0x..." hex)
976
958
  * @param {string} [params.elGamalPrivateKey] - ElGamal private key (base64) for auto-proof
@@ -1055,8 +1037,8 @@ export class AnonymousTransferClient {
1055
1037
  const domain = this._buildDomain();
1056
1038
  const types = {
1057
1039
  AnonymousTransferToAnonymous: [
1058
- { name: "senderId", type: "uint64" },
1059
- { name: "recipientId", type: "uint64" },
1040
+ { name: "senderId", type: "string" },
1041
+ { name: "recipientId", type: "string" },
1060
1042
  { name: "token", type: "address" },
1061
1043
  { name: "proofHash", type: "bytes32" },
1062
1044
  { name: "authNonce", type: "uint256" },
@@ -1064,8 +1046,8 @@ export class AnonymousTransferClient {
1064
1046
  ],
1065
1047
  };
1066
1048
  const value = {
1067
- senderId: BigInt(senderAccountId),
1068
- recipientId: BigInt(recipientId),
1049
+ senderId: String(senderAccountId),
1050
+ recipientId: String(recipientId),
1069
1051
  token,
1070
1052
  proofHash,
1071
1053
  authNonce,
@@ -1075,8 +1057,8 @@ export class AnonymousTransferClient {
1075
1057
  const signature = await authWallet.signTypedData(domain, types, value);
1076
1058
 
1077
1059
  return await this._fetch("POST", "/v1/anonymous/transfers/anonymous", {
1078
- sender_id: Number(senderAccountId),
1079
- recipient_id: Number(recipientId),
1060
+ sender_id: senderAccountId,
1061
+ recipient_id: recipientId,
1080
1062
  token,
1081
1063
  proof: proofHex,
1082
1064
  auth_nonce: String(authNonce),
@@ -1097,7 +1079,7 @@ export class AnonymousTransferClient {
1097
1079
  * this to move the pending credit into their available balance.
1098
1080
  *
1099
1081
  * @param {ethers.Wallet|ethers.Signer} authWallet
1100
- * @param {number|bigint} accountId
1082
+ * @param {string} accountId
1101
1083
  * @param {Object} [options]
1102
1084
  * @param {number} [options.deadlineOffset=3600]
1103
1085
  * @returns {Promise<{request_id:string, tx_hash:string, status:string}>}
@@ -1111,13 +1093,13 @@ export class AnonymousTransferClient {
1111
1093
  const domain = this._buildDomain();
1112
1094
  const types = {
1113
1095
  AnonymousApplyPending: [
1114
- { name: "accountId", type: "uint64" },
1096
+ { name: "accountId", type: "string" },
1115
1097
  { name: "authNonce", type: "uint256" },
1116
1098
  { name: "deadline", type: "uint256" },
1117
1099
  ],
1118
1100
  };
1119
1101
  const value = {
1120
- accountId: BigInt(accountId),
1102
+ accountId: String(accountId),
1121
1103
  authNonce,
1122
1104
  deadline: BigInt(deadline),
1123
1105
  };
@@ -1125,7 +1107,7 @@ export class AnonymousTransferClient {
1125
1107
  const signature = await authWallet.signTypedData(domain, types, value);
1126
1108
 
1127
1109
  return await this._fetch("POST", "/v1/anonymous/apply", {
1128
- account_id: Number(accountId),
1110
+ account_id: accountId,
1129
1111
  auth_nonce: String(authNonce),
1130
1112
  deadline: String(deadline),
1131
1113
  signature,
@@ -1147,7 +1129,7 @@ export class AnonymousTransferClient {
1147
1129
  * **Manual proof mode**: provide a pre-computed `proof` hex string from `generateWithdrawProof()`.
1148
1130
  *
1149
1131
  * @param {ethers.Wallet|ethers.Signer} authWallet - Authorised signer for the anonymous account
1150
- * @param {number|bigint} accountId
1132
+ * @param {string} accountId
1151
1133
  * @param {Object} params
1152
1134
  * @param {string} params.destination - Destination EVM address
1153
1135
  * @param {string} params.token - Token address
@@ -1232,7 +1214,7 @@ export class AnonymousTransferClient {
1232
1214
  const domain = this._buildDomain();
1233
1215
  const types = {
1234
1216
  AnonymousWithdraw: [
1235
- { name: "accountId", type: "uint64" },
1217
+ { name: "accountId", type: "string" },
1236
1218
  { name: "destination", type: "address" },
1237
1219
  { name: "token", type: "address" },
1238
1220
  { name: "plainAmount", type: "uint256" },
@@ -1242,7 +1224,7 @@ export class AnonymousTransferClient {
1242
1224
  ],
1243
1225
  };
1244
1226
  const value = {
1245
- accountId: BigInt(accountId),
1227
+ accountId: String(accountId),
1246
1228
  destination,
1247
1229
  token,
1248
1230
  plainAmount: withdrawAmountContractScale,
@@ -1254,7 +1236,7 @@ export class AnonymousTransferClient {
1254
1236
  const signature = await authWallet.signTypedData(domain, types, value);
1255
1237
 
1256
1238
  return await this._fetch("POST", "/v1/anonymous/withdraw", {
1257
- account_id: Number(accountId),
1239
+ account_id: accountId,
1258
1240
  destination,
1259
1241
  token,
1260
1242
  plain_amount: String(withdrawAmountContractScale),
@@ -1273,7 +1255,7 @@ export class AnonymousTransferClient {
1273
1255
  /**
1274
1256
  * Get total, available, and pending balance (contract scale).
1275
1257
  *
1276
- * @param {number|bigint} accountId
1258
+ * @param {string} accountId
1277
1259
  * @param {string} tokenAddress
1278
1260
  * @param {string} elGamalPrivateKey
1279
1261
  * @returns {Promise<{ amount: number, available: number, pending: number }>}
package/src/constants.js CHANGED
@@ -25,7 +25,7 @@ export const TEMPO_FEE_TOKEN_ADDRESS =
25
25
  "0x20c0000000000000000000000000000000000000";
26
26
  export const STABLETRUST_CONTRACTS_BY_CHAIN_ID = Object.freeze({
27
27
  2201: "0xA98e5ba75Bb44459916D52Abf1604caB3d98CC4B", //Stable
28
- 5042002: "0xdCF31bd9f325C34E0fb346b1975E141D99AEf731", //Arc
28
+ 5042002: "0x0E56ade5A9d05D5fDa3ffe08Df64cFc0eD597D94", //Arc
29
29
  84532: "0xF66A0a1670F14AE5D1852B4E7d1e4C693b2Accfd", //Base
30
30
  11155111: "0xa066b5C30382110d19925108BBa1Eef613a3A041", //Ethereum
31
31
  421614: "0xbda65d65A7833D28F9391FF01d0b212B75538Cf2", //Arbitrum
package/src/index.d.ts CHANGED
@@ -84,7 +84,7 @@ declare module "@fairblock/stabletrust" {
84
84
  }
85
85
 
86
86
  export interface TransferToAnonymousParams {
87
- recipientId: number | bigint;
87
+ recipientId: string;
88
88
  token: string;
89
89
  /** Pre-computed ZK proof hex. Required if elGamalPrivateKey is not provided. */
90
90
  proof?: string;
@@ -167,18 +167,13 @@ declare module "@fairblock/stabletrust" {
167
167
  /**
168
168
  * Read the current authNonce for an anonymous account.
169
169
  */
170
- getAuthNonce(accountId: number | bigint): Promise<bigint>;
171
-
172
- /**
173
- * Read the next anonymous account ID that will be assigned.
174
- */
175
- getNextAccountId(): Promise<bigint>;
170
+ getAuthNonce(accountId: string): Promise<bigint>;
176
171
 
177
172
  /**
178
173
  * Check whether an address is an authorised signer for an anonymous account.
179
174
  */
180
175
  isAuthorizedSigner(
181
- accountId: number | bigint,
176
+ accountId: string,
182
177
  signerAddress: string,
183
178
  ): Promise<boolean>;
184
179
 
@@ -211,7 +206,7 @@ declare module "@fairblock/stabletrust" {
211
206
  */
212
207
  deriveAnonymousKeys(
213
208
  authWallet: ethers.Wallet | ethers.Signer,
214
- accountId: number | bigint,
209
+ accountId: string,
215
210
  ): Promise<Keys>;
216
211
 
217
212
  // ── proof generation ────────────────────────────────────────────
@@ -238,10 +233,12 @@ declare module "@fairblock/stabletrust" {
238
233
 
239
234
  /**
240
235
  * Create a new anonymous account. The relay pays gas.
236
+ * @param accountId Caller-chosen account ID (non-empty string, case-sensitive)
241
237
  * @param elgamalPublicKey Base64 or "0x"-prefixed hex (32 bytes)
242
238
  */
243
239
  createAccount(
244
240
  authWallet: ethers.Wallet | ethers.Signer,
241
+ accountId: string,
245
242
  elgamalPublicKey: string,
246
243
  options?: DeadlineOptions,
247
244
  ): Promise<FairycloakResponse>;
@@ -252,7 +249,7 @@ declare module "@fairblock/stabletrust" {
252
249
  */
253
250
  updateAuthKeys(
254
251
  authWallet: ethers.Wallet | ethers.Signer,
255
- accountId: number | bigint,
252
+ accountId: string,
256
253
  keys: UpdateAuthKeysParams,
257
254
  options?: DeadlineOptions,
258
255
  ): Promise<FairycloakResponse>;
@@ -263,7 +260,7 @@ declare module "@fairblock/stabletrust" {
263
260
  */
264
261
  deposit(
265
262
  authWallet: ethers.Wallet,
266
- accountId: number | bigint,
263
+ accountId: string,
267
264
  tokenAddress: string,
268
265
  amount: bigint | string | number,
269
266
  options?: DepositOptions,
@@ -277,7 +274,7 @@ declare module "@fairblock/stabletrust" {
277
274
  */
278
275
  transferToPublic(
279
276
  authWallet: ethers.Wallet | ethers.Signer,
280
- accountId: number | bigint,
277
+ accountId: string,
281
278
  params: TransferToPublicParams,
282
279
  options?: DeadlineOptions,
283
280
  ): Promise<FairycloakResponse>;
@@ -290,7 +287,7 @@ declare module "@fairblock/stabletrust" {
290
287
  */
291
288
  transferToAnonymous(
292
289
  authWallet: ethers.Wallet | ethers.Signer,
293
- senderAccountId: number | bigint,
290
+ senderAccountId: string,
294
291
  params: TransferToAnonymousParams,
295
292
  options?: DeadlineOptions,
296
293
  ): Promise<FairycloakResponse>;
@@ -300,7 +297,7 @@ declare module "@fairblock/stabletrust" {
300
297
  */
301
298
  applyPending(
302
299
  authWallet: ethers.Wallet | ethers.Signer,
303
- accountId: number | bigint,
300
+ accountId: string,
304
301
  options?: DeadlineOptions,
305
302
  ): Promise<FairycloakResponse>;
306
303
 
@@ -313,7 +310,7 @@ declare module "@fairblock/stabletrust" {
313
310
  */
314
311
  withdraw(
315
312
  authWallet: ethers.Wallet | ethers.Signer,
316
- accountId: number | bigint,
313
+ accountId: string,
317
314
  params: WithdrawParams,
318
315
  options?: DeadlineOptions,
319
316
  ): Promise<FairycloakResponse>;