@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.
- package/examples/anonymous-flow.js +35 -31
- package/package.json +1 -1
- package/src/anonymous-client.js +47 -65
- package/src/constants.js +1 -1
- package/src/index.d.ts +12 -15
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Anonymous Confidential Transfer — Basic Flow
|
|
3
3
|
*
|
|
4
|
-
* [1]
|
|
5
|
-
* [2]
|
|
6
|
-
* [3]
|
|
7
|
-
* [4]
|
|
8
|
-
* [5]
|
|
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]
|
|
120
|
+
// ── [1] Generate account IDs ─────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
console.log("\n── [1] Generate anonymous account IDs ──────────────────");
|
|
126
123
|
|
|
127
|
-
|
|
124
|
+
const anon1Id = randomUUID();
|
|
125
|
+
const anon2Id = randomUUID();
|
|
126
|
+
log("anon1 id:", anon1Id);
|
|
127
|
+
log("anon2 id:", anon2Id);
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
log("
|
|
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
|
-
// ── [
|
|
190
|
+
// ── [4] Deposit ──────────────────────────────────────────────────────────────
|
|
189
191
|
|
|
190
|
-
console.log("\n── [
|
|
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
|
-
// ── [
|
|
221
|
+
// ── [5] Transfer anon1 → anon2 ───────────────────────────────────────────────
|
|
220
222
|
|
|
221
|
-
console.log("\n── [
|
|
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
|
-
// ── [
|
|
266
|
+
// ── [6] Apply pending for anon2 ──────────────────────────────────────────────
|
|
265
267
|
|
|
266
|
-
console.log("\n── [
|
|
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
|
-
// ── [
|
|
292
|
+
// ── [7] Withdraw anon2 → public address ──────────────────────────────────────
|
|
291
293
|
|
|
292
|
-
console.log("\n── [
|
|
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
package/src/anonymous-client.js
CHANGED
|
@@ -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(
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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: "
|
|
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", "
|
|
367
|
+
["uint256", "address", "string", "string"],
|
|
390
368
|
[
|
|
391
369
|
this.chainId,
|
|
392
370
|
this.diamondAddress,
|
|
393
|
-
|
|
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:
|
|
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 {
|
|
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: "
|
|
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:
|
|
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:
|
|
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 {
|
|
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: "
|
|
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:
|
|
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
|
-
|
|
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 {
|
|
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.
|
|
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: "
|
|
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:
|
|
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:
|
|
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 {
|
|
953
|
+
* @param {string} senderAccountId
|
|
972
954
|
* @param {Object} params
|
|
973
|
-
* @param {
|
|
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: "
|
|
1059
|
-
{ name: "recipientId", type: "
|
|
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:
|
|
1068
|
-
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:
|
|
1079
|
-
recipient_id:
|
|
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 {
|
|
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: "
|
|
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:
|
|
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:
|
|
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 {
|
|
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: "
|
|
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:
|
|
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:
|
|
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 {
|
|
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: "
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
313
|
+
accountId: string,
|
|
317
314
|
params: WithdrawParams,
|
|
318
315
|
options?: DeadlineOptions,
|
|
319
316
|
): Promise<FairycloakResponse>;
|