@fairblock/stabletrust 1.0.13 → 1.0.15
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/README.md +24 -22
- package/examples/complete-flow.js +32 -16
- package/examples/constants.js +6 -0
- package/examples/simple-snippets.js +9 -4
- package/package.json +1 -1
- package/src/client.js +40 -21
- package/src/constants.js +7 -6
package/README.md
CHANGED
|
@@ -38,12 +38,12 @@ The following contract addresses are available for confidential transfers on tes
|
|
|
38
38
|
|
|
39
39
|
| Network(Testnet) | Chain ID | Contract Address |
|
|
40
40
|
| :--------------- | :------- | :------------------------------------------- |
|
|
41
|
-
| Stable | 2201 | `
|
|
42
|
-
| Arc | 1244 | `
|
|
43
|
-
| Base | 84532 | `
|
|
44
|
-
| Ethereum | 11155111 | `
|
|
45
|
-
| Arbitrum | 421614 | `
|
|
46
|
-
| Tempo | 42431 | `
|
|
41
|
+
| Stable | 2201 | `0xb0b461aFA69b715d842c7fAb602f50D4cef83fe5` |
|
|
42
|
+
| Arc | 1244 | `0xEa837218c7Ccd9eA1BCfB640e5c6aFE59952b4FA` |
|
|
43
|
+
| Base | 84532 | `0x1a06530765e942a1D26B74d9558e9a1EdA615867` |
|
|
44
|
+
| Ethereum | 11155111 | `0xABEa3399873b80f528Ee76286087b45ed38Fbf97` |
|
|
45
|
+
| Arbitrum | 421614 | `0x2131De660C6be8b535E6f17E171bFf7143E9E9F4` |
|
|
46
|
+
| Tempo | 42431 | `0xF3525FF8F592883f8fA2d89EfBe85637955Df487` |
|
|
47
47
|
|
|
48
48
|
## Usage
|
|
49
49
|
|
|
@@ -97,21 +97,23 @@ const tempoClient = new ConfidentialTransferClient(
|
|
|
97
97
|
|
|
98
98
|
**Note on Tempo Chain**: The Tempo network (chainId 42431) uses token-based fees instead of native currency. The SDK automatically handles fee payment using PathUSD when detected.
|
|
99
99
|
|
|
100
|
-
### Token Denomination
|
|
100
|
+
### Token Denomination
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
When interacting with the SDK for deposit, transfer, and withdraw operations, you should parse the token amount using the underlying token's decimals. When displaying the fetched balance, format it using the token's decimals.
|
|
103
103
|
|
|
104
|
-
- To deposit
|
|
105
|
-
- To display a balance,
|
|
104
|
+
- To deposit, transfer, or withdraw tokens, parse the amount using `ethers.parseUnits(amount, tokenDecimals)`.
|
|
105
|
+
- To display a balance, format the raw amount using `ethers.formatUnits(balance.amount, tokenDecimals)`.
|
|
106
106
|
|
|
107
107
|
**Recommended helpers (consistent with examples):**
|
|
108
108
|
|
|
109
109
|
```javascript
|
|
110
|
-
//
|
|
111
|
-
const
|
|
110
|
+
// Fetch or define your token's decimals (e.g., 6 for USDC)
|
|
111
|
+
const tokenDecimals = 6;
|
|
112
|
+
|
|
113
|
+
const amountToDeposit = ethers.parseUnits("0.1", tokenDecimals);
|
|
112
114
|
await client.confidentialDeposit(signer, tokenAddress, amountToDeposit);
|
|
113
115
|
|
|
114
|
-
const amountToTransfer = ethers.parseUnits("0.05",
|
|
116
|
+
const amountToTransfer = ethers.parseUnits("0.05", tokenDecimals);
|
|
115
117
|
await client.confidentialTransfer(
|
|
116
118
|
signer,
|
|
117
119
|
recipientAddress,
|
|
@@ -119,7 +121,7 @@ await client.confidentialTransfer(
|
|
|
119
121
|
amountToTransfer,
|
|
120
122
|
);
|
|
121
123
|
|
|
122
|
-
const amountToWithdraw = ethers.parseUnits("0.02",
|
|
124
|
+
const amountToWithdraw = ethers.parseUnits("0.02", tokenDecimals);
|
|
123
125
|
await client.withdraw(signer, tokenAddress, amountToWithdraw);
|
|
124
126
|
|
|
125
127
|
const balance = await client.getConfidentialBalance(
|
|
@@ -127,7 +129,7 @@ const balance = await client.getConfidentialBalance(
|
|
|
127
129
|
privateKey,
|
|
128
130
|
tokenAddress,
|
|
129
131
|
);
|
|
130
|
-
console.log("Balance:", ethers.formatUnits(balance.amount,
|
|
132
|
+
console.log("Balance:", ethers.formatUnits(balance.amount, tokenDecimals));
|
|
131
133
|
```
|
|
132
134
|
|
|
133
135
|
### Key Functions
|
|
@@ -162,9 +164,9 @@ Retrieves the decrypted available and pending balances for a specific token, plu
|
|
|
162
164
|
- `privateKey` (string): The private key for decryption.
|
|
163
165
|
- `tokenAddress` (string): The token contract address.
|
|
164
166
|
- **Returns**: An object containing:
|
|
165
|
-
- `amount` (
|
|
166
|
-
- `available` (object): `{ amount, ciphertext }`
|
|
167
|
-
- `pending` (object): `{ amount, ciphertext }`
|
|
167
|
+
- `amount` (bigint): The total (available + pending)
|
|
168
|
+
- `available` (object): `{ amount, ciphertext }`
|
|
169
|
+
- `pending` (object): `{ amount, ciphertext }`
|
|
168
170
|
|
|
169
171
|
#### `confidentialDeposit(signer, tokenAddress, amount, options)`
|
|
170
172
|
|
|
@@ -173,7 +175,7 @@ Deposits a specified amount of ERC20 tokens into the confidential contract, conv
|
|
|
173
175
|
- **Parameters**:
|
|
174
176
|
- `signer` (ethers.Signer): The transaction signer.
|
|
175
177
|
- `tokenAddress` (string): The contract address of the ERC20 token.
|
|
176
|
-
- `amount` (bigint | string | number): The amount to deposit
|
|
178
|
+
- `amount` (bigint | string | number): The amount to deposit, parsed with token decimals.
|
|
177
179
|
- `options` (object, optional):
|
|
178
180
|
- `waitForFinalization` (boolean): Wait for deposit finalization. Default: `true`
|
|
179
181
|
- **Returns**: A transaction receipt.
|
|
@@ -186,7 +188,7 @@ Executes a confidential transfer of tokens from the sender to a recipient. The a
|
|
|
186
188
|
- `signer` (ethers.Signer): The sender's signer.
|
|
187
189
|
- `recipientAddress` (string): The public address of the recipient.
|
|
188
190
|
- `tokenAddress` (string): The token contract address.
|
|
189
|
-
- `amount` (number): The amount to transfer
|
|
191
|
+
- `amount` (bigint | string | number): The amount to transfer, parsed with token decimals.
|
|
190
192
|
- `options` (object, optional):
|
|
191
193
|
- `useOffchainVerify` (boolean): Use offchain verification. Default: `false`
|
|
192
194
|
- `waitForFinalization` (boolean): Wait for transfer finalization. Default: `true`
|
|
@@ -199,7 +201,7 @@ Withdraws funds from the confidential "available" balance back to the public lay
|
|
|
199
201
|
- **Parameters**:
|
|
200
202
|
- `signer` (ethers.Signer): The user's signer.
|
|
201
203
|
- `tokenAddress` (string): The token contract address.
|
|
202
|
-
- `amount` (number): The amount to withdraw
|
|
204
|
+
- `amount` (bigint | string | number): The amount to withdraw, parsed with token decimals.
|
|
203
205
|
- `options` (object, optional):
|
|
204
206
|
- `useOffchainVerify` (boolean): Use offchain verification. Default: `false`
|
|
205
207
|
- `waitForFinalization` (boolean): Wait for withdrawal finalization. Default: `true`
|
|
@@ -288,7 +290,7 @@ When using the StableTrust SDK, follow these best practices to ensure the securi
|
|
|
288
290
|
|
|
289
291
|
5. **Balance Verification**
|
|
290
292
|
|
|
291
|
-
- Check available balance before initiating transfers
|
|
293
|
+
- Check available balance before initiating transfers
|
|
292
294
|
- Be aware of transaction fees that may vary by network
|
|
293
295
|
- On Tempo chain, ensure sufficient PathUSD balance for fee payment
|
|
294
296
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ethers } from "ethers";
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
import { ConfidentialTransferClient } from "@fairblock/stabletrust";
|
|
4
|
-
|
|
4
|
+
import { ERC20_ABI } from "./constants.js";
|
|
5
5
|
dotenv.config();
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -13,7 +13,7 @@ dotenv.config();
|
|
|
13
13
|
|
|
14
14
|
// Optional override for custom confidential contract deployments.
|
|
15
15
|
const CONTRACT_ADDRESS =
|
|
16
|
-
process.env.CONTRACT_ADDRESS || "
|
|
16
|
+
process.env.CONTRACT_ADDRESS || "0xb0b461aFA69b715d842c7fAb602f50D4cef83fe5";
|
|
17
17
|
// Standard ERC20 token contract. Any ERC20 on this chain ID can be used.
|
|
18
18
|
const TOKEN_ADDRESS =
|
|
19
19
|
process.env.TOKEN_ADDRESS || "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9";
|
|
@@ -55,6 +55,9 @@ async function main() {
|
|
|
55
55
|
provider,
|
|
56
56
|
);
|
|
57
57
|
|
|
58
|
+
const tokenContract = new ethers.Contract(TOKEN_ADDRESS, ERC20_ABI, provider);
|
|
59
|
+
const tokenDecimals = await tokenContract.decimals();
|
|
60
|
+
|
|
58
61
|
console.log("Sender Address:", sender.address);
|
|
59
62
|
console.log("Recipient Address:", recipient.address);
|
|
60
63
|
|
|
@@ -62,7 +65,7 @@ async function main() {
|
|
|
62
65
|
const recipientKeys = await client.ensureAccount(recipient);
|
|
63
66
|
|
|
64
67
|
// 1. DEPOSIT PHASE
|
|
65
|
-
const depositAmount = ethers.parseUnits("0.1",
|
|
68
|
+
const depositAmount = ethers.parseUnits("0.1", tokenDecimals);
|
|
66
69
|
const senderConfidentialBalanceBefore = await client.getConfidentialBalance(
|
|
67
70
|
sender.address,
|
|
68
71
|
senderKeys.privateKey,
|
|
@@ -71,7 +74,7 @@ async function main() {
|
|
|
71
74
|
|
|
72
75
|
console.log(
|
|
73
76
|
"Sender Confidential Balance (Pre-Deposit):",
|
|
74
|
-
ethers.formatUnits(senderConfidentialBalanceBefore.amount,
|
|
77
|
+
ethers.formatUnits(senderConfidentialBalanceBefore.amount, tokenDecimals),
|
|
75
78
|
);
|
|
76
79
|
|
|
77
80
|
console.log("Depositing 0.1 tokens into confidential contract...");
|
|
@@ -91,11 +94,11 @@ async function main() {
|
|
|
91
94
|
);
|
|
92
95
|
console.log(
|
|
93
96
|
"Sender Confidential Balance (Post-Deposit):",
|
|
94
|
-
ethers.formatUnits(senderConfidentialBalanceAfterDep.amount,
|
|
97
|
+
ethers.formatUnits(senderConfidentialBalanceAfterDep.amount, tokenDecimals),
|
|
95
98
|
);
|
|
96
99
|
|
|
97
100
|
// 2. TRANSFER PHASE
|
|
98
|
-
const transferAmount = ethers.parseUnits("0.05",
|
|
101
|
+
const transferAmount = ethers.parseUnits("0.05", tokenDecimals);
|
|
99
102
|
const senderConfidentialBalanceBeforeTx = await client.getConfidentialBalance(
|
|
100
103
|
sender.address,
|
|
101
104
|
senderKeys.privateKey,
|
|
@@ -111,11 +114,14 @@ async function main() {
|
|
|
111
114
|
|
|
112
115
|
console.log(
|
|
113
116
|
"Sender Confidential Balance (Pre-Transfer):",
|
|
114
|
-
ethers.formatUnits(senderConfidentialBalanceBeforeTx.amount,
|
|
117
|
+
ethers.formatUnits(senderConfidentialBalanceBeforeTx.amount, tokenDecimals),
|
|
115
118
|
);
|
|
116
119
|
console.log(
|
|
117
120
|
"Recipient Confidential Balance (Pre-Transfer):",
|
|
118
|
-
ethers.formatUnits(
|
|
121
|
+
ethers.formatUnits(
|
|
122
|
+
recipientConfidentialBalanceBeforeTx.amount,
|
|
123
|
+
tokenDecimals,
|
|
124
|
+
),
|
|
119
125
|
);
|
|
120
126
|
|
|
121
127
|
console.log("Transferring 0.05 tokens confidentially to recipient...");
|
|
@@ -152,22 +158,22 @@ async function main() {
|
|
|
152
158
|
|
|
153
159
|
console.log(
|
|
154
160
|
"Sender Confidential Balance (Post-Transfer):",
|
|
155
|
-
ethers.formatUnits(senderConfidentialBalanceAfterTx.amount,
|
|
161
|
+
ethers.formatUnits(senderConfidentialBalanceAfterTx.amount, tokenDecimals),
|
|
156
162
|
);
|
|
157
163
|
console.log(
|
|
158
164
|
"Recipient Confidential Balance (Post-Transfer):",
|
|
159
|
-
ethers.formatUnits(
|
|
165
|
+
ethers.formatUnits(
|
|
166
|
+
recipientConfidentialBalanceAfterTx.amount,
|
|
167
|
+
tokenDecimals,
|
|
168
|
+
),
|
|
160
169
|
"\n",
|
|
161
170
|
);
|
|
162
171
|
|
|
163
172
|
// 3. WITHDRAW PHASE
|
|
164
|
-
const withdrawAmount = ethers.parseUnits("0.05",
|
|
173
|
+
const withdrawAmount = ethers.parseUnits("0.05", tokenDecimals);
|
|
165
174
|
console.log(
|
|
166
175
|
"Withdrawing 0.05 tokens from confidential contract to recipient's public balance...",
|
|
167
176
|
);
|
|
168
|
-
const withdrawRes = await trackPerformance("WITHDRAW_TOKENS", () =>
|
|
169
|
-
client.withdraw(recipient, TOKEN_ADDRESS, withdrawAmount),
|
|
170
|
-
);
|
|
171
177
|
let recipientConfidentialBalanceBeforeWithdraw =
|
|
172
178
|
await client.getConfidentialBalance(
|
|
173
179
|
recipient.address,
|
|
@@ -177,8 +183,15 @@ async function main() {
|
|
|
177
183
|
|
|
178
184
|
console.log(
|
|
179
185
|
"Recipient Confidential Balance (Pre-Withdraw):",
|
|
180
|
-
ethers.formatUnits(
|
|
186
|
+
ethers.formatUnits(
|
|
187
|
+
recipientConfidentialBalanceBeforeWithdraw.amount,
|
|
188
|
+
tokenDecimals,
|
|
189
|
+
),
|
|
190
|
+
);
|
|
191
|
+
const withdrawRes = await trackPerformance("WITHDRAW_TOKENS", () =>
|
|
192
|
+
client.withdraw(recipient, TOKEN_ADDRESS, withdrawAmount),
|
|
181
193
|
);
|
|
194
|
+
|
|
182
195
|
const withdrawHash = withdrawRes.result.hash;
|
|
183
196
|
console.log(`Transaction Hash: ${withdrawHash}`);
|
|
184
197
|
console.log(`View Transaction: ${EXPLORER_URL}${withdrawHash}`);
|
|
@@ -192,7 +205,10 @@ async function main() {
|
|
|
192
205
|
|
|
193
206
|
console.log(
|
|
194
207
|
"Recipient Confidential Balance (Final):",
|
|
195
|
-
ethers.formatUnits(
|
|
208
|
+
ethers.formatUnits(
|
|
209
|
+
recipientConfidentialBalanceAfterWithdraw.amount,
|
|
210
|
+
tokenDecimals,
|
|
211
|
+
),
|
|
196
212
|
);
|
|
197
213
|
|
|
198
214
|
console.log("\n=== Complete Flow Execution Finished ===");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const ERC20_ABI = [
|
|
2
|
+
"function approve(address spender, uint256 amount) external returns (bool)",
|
|
3
|
+
"function allowance(address owner, address spender) external view returns (uint256)",
|
|
4
|
+
"function balanceOf(address account) external view returns (uint256)",
|
|
5
|
+
"function decimals() external view returns (uint8)",
|
|
6
|
+
];
|
|
@@ -19,9 +19,10 @@ async function minimalFlow() {
|
|
|
19
19
|
// 2. Initialize Confidential Accounts (View Keys)
|
|
20
20
|
await client.ensureAccount(sender);
|
|
21
21
|
await client.ensureAccount(recipient);
|
|
22
|
-
|
|
22
|
+
const tokenContract = new ethers.Contract(TOKEN_ADDRESS, ERC20_ABI, provider);
|
|
23
|
+
const tokenDecimals = await tokenContract.decimals();
|
|
23
24
|
const TOKEN = "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9";
|
|
24
|
-
const amount = ethers.parseUnits("0.1",
|
|
25
|
+
const amount = ethers.parseUnits("0.1", tokenDecimals);
|
|
25
26
|
let res;
|
|
26
27
|
// 3. DEPOSIT: Move public ERC20 into the confidential contract
|
|
27
28
|
res = await client.confidentialDeposit(sender, TOKEN, amount);
|
|
@@ -32,11 +33,15 @@ async function minimalFlow() {
|
|
|
32
33
|
sender,
|
|
33
34
|
recipient.address,
|
|
34
35
|
TOKEN,
|
|
35
|
-
ethers.parseUnits("0.05",
|
|
36
|
+
ethers.parseUnits("0.05", tokenDecimals),
|
|
36
37
|
);
|
|
37
38
|
console.log("Transfer TX Hash:", EXPLORER_URL + res.hash);
|
|
38
39
|
// 5. WITHDRAW: Convert confidential balance back to public ERC20
|
|
39
|
-
res = await client.withdraw(
|
|
40
|
+
res = await client.withdraw(
|
|
41
|
+
recipient,
|
|
42
|
+
TOKEN,
|
|
43
|
+
ethers.parseUnits("0.05", tokenDecimals),
|
|
44
|
+
);
|
|
40
45
|
console.log("Withdraw TX Hash:", EXPLORER_URL + res.hash);
|
|
41
46
|
console.log("Confidential flow complete.");
|
|
42
47
|
}
|
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -288,18 +288,24 @@ export class ConfidentialTransferClient {
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
if ((!c1 || c1 === "0x") && (!c2 || c2 === "0x")) {
|
|
291
|
-
return { amount:
|
|
291
|
+
return { amount: 0n, ciphertext: null };
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
const wasm = await this._getWasm();
|
|
295
295
|
const ciphertext = combineCiphertext(c1, c2);
|
|
296
|
-
const
|
|
296
|
+
const contractAmount = decryptCiphertext(
|
|
297
297
|
ciphertext,
|
|
298
298
|
privateKey,
|
|
299
299
|
wasm.decrypt_ciphertext,
|
|
300
300
|
);
|
|
301
|
+
const tokenAmount = ethers.formatUnits(contractAmount, 2);
|
|
302
|
+
const tokenContract = this._getTokenContract(tokenAddress);
|
|
303
|
+
const tokenUnits = await tokenContract.decimals();
|
|
301
304
|
|
|
302
|
-
return {
|
|
305
|
+
return {
|
|
306
|
+
amount: ethers.parseUnits(tokenAmount, Number(tokenUnits)),
|
|
307
|
+
ciphertext,
|
|
308
|
+
};
|
|
303
309
|
} catch (error) {
|
|
304
310
|
throw new Error(`Failed to get balance: ${error.message}`);
|
|
305
311
|
}
|
|
@@ -360,8 +366,11 @@ export class ConfidentialTransferClient {
|
|
|
360
366
|
tokenAddress,
|
|
361
367
|
"deposit",
|
|
362
368
|
);
|
|
363
|
-
|
|
369
|
+
|
|
364
370
|
const tokenContract = this._getTokenContract(tokenAddress);
|
|
371
|
+
const tokenDecimals = await tokenContract.decimals();
|
|
372
|
+
const depositAmount =
|
|
373
|
+
(BigInt(amount) * 100n) / 10n ** BigInt(tokenDecimals);
|
|
365
374
|
|
|
366
375
|
// Check token balance and allowance in parallel
|
|
367
376
|
const [tokenBalance, allowance] = await Promise.all([
|
|
@@ -370,11 +379,11 @@ export class ConfidentialTransferClient {
|
|
|
370
379
|
]);
|
|
371
380
|
if (tokenBalance < depositAmount) {
|
|
372
381
|
throw new Error(
|
|
373
|
-
`Insufficient token balance. Required: ${
|
|
382
|
+
`Insufficient token balance. Required: ${amount}, Available: ${tokenBalance}`,
|
|
374
383
|
);
|
|
375
384
|
}
|
|
376
385
|
|
|
377
|
-
if (allowance <
|
|
386
|
+
if (allowance < amount) {
|
|
378
387
|
const approveTx = await tokenContract
|
|
379
388
|
.connect(wallet)
|
|
380
389
|
.approve(this.config.contractAddress, ethers.MaxUint256);
|
|
@@ -442,6 +451,10 @@ export class ConfidentialTransferClient {
|
|
|
442
451
|
if (!amount || amount <= 0) {
|
|
443
452
|
throw new Error("Transfer amount must be greater than 0");
|
|
444
453
|
}
|
|
454
|
+
const tokenContract = this._getTokenContract(tokenAddress);
|
|
455
|
+
const tokenDecimals = await tokenContract.decimals();
|
|
456
|
+
const transferAmount =
|
|
457
|
+
(BigInt(amount) * 100n) / 10n ** BigInt(tokenDecimals);
|
|
445
458
|
|
|
446
459
|
const senderAddress = await senderWallet.getAddress();
|
|
447
460
|
|
|
@@ -498,28 +511,28 @@ export class ConfidentialTransferClient {
|
|
|
498
511
|
"Current balance ciphertext is required. Did you call getConfidentialBalance()?",
|
|
499
512
|
);
|
|
500
513
|
}
|
|
501
|
-
if (balanceSummary.amount < amount) {
|
|
514
|
+
if (balanceSummary.amount < BigInt(amount)) {
|
|
502
515
|
throw new Error(
|
|
503
516
|
`Insufficient balance. Required: ${amount}, Total: ${balanceSummary.amount}`,
|
|
504
517
|
);
|
|
505
518
|
}
|
|
506
519
|
if (
|
|
507
520
|
derivedCurrentBalance === undefined ||
|
|
508
|
-
derivedCurrentBalance < amount
|
|
521
|
+
derivedCurrentBalance < BigInt(amount)
|
|
509
522
|
) {
|
|
510
523
|
throw new Error(
|
|
511
524
|
`Insufficient balance. Required: ${amount}, Available: ${derivedCurrentBalance}`,
|
|
512
525
|
);
|
|
513
526
|
}
|
|
514
527
|
|
|
528
|
+
const currentBalanceContractScale =
|
|
529
|
+
(BigInt(derivedCurrentBalance) * 100n) / 10n ** BigInt(tokenDecimals);
|
|
530
|
+
|
|
515
531
|
// Generate proof
|
|
516
532
|
const proofInput = {
|
|
517
533
|
current_balance_ciphertext: derivedCurrentBalanceCiphertext,
|
|
518
|
-
current_balance:
|
|
519
|
-
|
|
520
|
-
? derivedCurrentBalance.toString()
|
|
521
|
-
: derivedCurrentBalance,
|
|
522
|
-
transfer_amount: typeof amount === "bigint" ? Number(amount) : amount,
|
|
534
|
+
current_balance: Number(currentBalanceContractScale),
|
|
535
|
+
transfer_amount: Number(transferAmount),
|
|
523
536
|
source_keypair: derivedSenderKeys.privateKey,
|
|
524
537
|
destination_pubkey: derivedRecipientPublicKey,
|
|
525
538
|
};
|
|
@@ -753,6 +766,11 @@ export class ConfidentialTransferClient {
|
|
|
753
766
|
throw new Error("Withdrawal amount must be greater than 0");
|
|
754
767
|
}
|
|
755
768
|
|
|
769
|
+
const tokenContract = this._getTokenContract(tokenAddress);
|
|
770
|
+
const tokenDecimals = await tokenContract.decimals();
|
|
771
|
+
const withdrawAmount =
|
|
772
|
+
(BigInt(amount) * 100n) / 10n ** BigInt(tokenDecimals);
|
|
773
|
+
|
|
756
774
|
// Auto-derive keys
|
|
757
775
|
const derivedKeys = await this._deriveKeys(wallet);
|
|
758
776
|
if (!derivedKeys?.privateKey) {
|
|
@@ -780,25 +798,25 @@ export class ConfidentialTransferClient {
|
|
|
780
798
|
"Current balance ciphertext is required. Did you call getConfidentialBalance()?",
|
|
781
799
|
);
|
|
782
800
|
}
|
|
783
|
-
if (balanceSummary.amount < amount) {
|
|
801
|
+
if (balanceSummary.amount < BigInt(amount)) {
|
|
784
802
|
throw new Error(
|
|
785
803
|
`Insufficient balance. Required: ${amount}, Total: ${balanceSummary.amount}`,
|
|
786
804
|
);
|
|
787
805
|
}
|
|
788
|
-
if (currentBalance === undefined || currentBalance < amount) {
|
|
806
|
+
if (currentBalance === undefined || currentBalance < BigInt(amount)) {
|
|
789
807
|
throw new Error(
|
|
790
808
|
`Insufficient balance. Required: ${amount}, Available: ${currentBalance}`,
|
|
791
809
|
);
|
|
792
810
|
}
|
|
793
811
|
|
|
812
|
+
const currentBalanceContractScale =
|
|
813
|
+
(BigInt(currentBalance) * 100n) / 10n ** BigInt(tokenDecimals);
|
|
814
|
+
|
|
794
815
|
// Generate withdrawal proof
|
|
795
816
|
const withdrawInput = {
|
|
796
817
|
current_balance_ciphertext: currentBalanceCiphertext,
|
|
797
|
-
current_balance:
|
|
798
|
-
|
|
799
|
-
? Number(currentBalance)
|
|
800
|
-
: currentBalance,
|
|
801
|
-
withdraw_amount: typeof amount === "bigint" ? Number(amount) : amount,
|
|
818
|
+
current_balance: Number(currentBalanceContractScale),
|
|
819
|
+
withdraw_amount: Number(withdrawAmount),
|
|
802
820
|
keypair: derivedKeys.privateKey,
|
|
803
821
|
};
|
|
804
822
|
|
|
@@ -819,7 +837,7 @@ export class ConfidentialTransferClient {
|
|
|
819
837
|
.connect(wallet)
|
|
820
838
|
.withdraw(
|
|
821
839
|
tokenAddress,
|
|
822
|
-
BigInt(
|
|
840
|
+
BigInt(withdrawAmount),
|
|
823
841
|
ethers.getBytes(encodeWithdrawProof(proof.data)),
|
|
824
842
|
useOffchainVerify,
|
|
825
843
|
);
|
|
@@ -933,6 +951,7 @@ export class ConfidentialTransferClient {
|
|
|
933
951
|
options = {},
|
|
934
952
|
) {
|
|
935
953
|
const { maxAttempts = 225, intervalMs = 400 } = options;
|
|
954
|
+
await sleep(1000);
|
|
936
955
|
|
|
937
956
|
try {
|
|
938
957
|
for (let i = 0; i < maxAttempts; i++) {
|
package/src/constants.js
CHANGED
|
@@ -18,18 +18,19 @@ export const ERC20_ABI = [
|
|
|
18
18
|
"function approve(address spender, uint256 amount) external returns (bool)",
|
|
19
19
|
"function allowance(address owner, address spender) external view returns (uint256)",
|
|
20
20
|
"function balanceOf(address account) external view returns (uint256)",
|
|
21
|
+
"function decimals() external view returns (uint8)",
|
|
21
22
|
];
|
|
22
23
|
|
|
23
24
|
export const TEMPO_FEE_TOKEN_ADDRESS =
|
|
24
25
|
"0x20c0000000000000000000000000000000000000";
|
|
25
26
|
|
|
26
27
|
export const STABLETRUST_CONTRACTS_BY_CHAIN_ID = Object.freeze({
|
|
27
|
-
2201: "
|
|
28
|
-
1244: "
|
|
29
|
-
84532: "
|
|
30
|
-
11155111: "
|
|
31
|
-
421614: "
|
|
32
|
-
42431: "
|
|
28
|
+
2201: "0xb0b461aFA69b715d842c7fAb602f50D4cef83fe5", //Stable
|
|
29
|
+
1244: "0xEa837218c7Ccd9eA1BCfB640e5c6aFE59952b4FA", //Arc
|
|
30
|
+
84532: "0x1a06530765e942a1D26B74d9558e9a1EdA615867", //Base
|
|
31
|
+
11155111: "0xABEa3399873b80f528Ee76286087b45ed38Fbf97", //Ethereum
|
|
32
|
+
421614: "0x2131De660C6be8b535E6f17E171bFf7143E9E9F4", //Arbitrum
|
|
33
|
+
42431: "0xF3525FF8F592883f8fA2d89EfBe85637955Df487", //Tempo
|
|
33
34
|
});
|
|
34
35
|
|
|
35
36
|
export function getStableTrustContractAddress(chainId) {
|