@fairblock/stabletrust 1.0.7 → 1.0.8
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 +65 -63
- package/examples/complete-flow.js +63 -94
- package/examples/simple-snippets.js +13 -11
- package/package.json +1 -1
- package/pkg/confidential_transfer_proof_generation.js +579 -483
- package/src/client.js +164 -77
- package/src/index.d.ts +14 -63
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ The following contract addresses are available for confidential transfers on tes
|
|
|
38
38
|
|
|
39
39
|
| Network | Chain ID | Contract Address |
|
|
40
40
|
| :------- | :------- | :------------------------------------------- |
|
|
41
|
-
| Stable | 2201 | `
|
|
41
|
+
| Stable | 2201 | `0x29E4fd434758b1677c10854Fa81C2fc496D76E62` |
|
|
42
42
|
| Arc | 1244 | `0x1Bf79BF5A32D6f3cdce3fe1A93c3fB222Bc93bb3` |
|
|
43
43
|
| Base | 84532 | `0x73D2bc5B5c7aF5C3726E7bEf0BD8b4931923fdA9` |
|
|
44
44
|
| Ethereum | 11155111 | `0xD765Dff7D734ABE09f88991A46BAb73ACa8910EF` |
|
|
@@ -94,17 +94,50 @@ const tempoClient = new ConfidentialTransferClient(
|
|
|
94
94
|
|
|
95
95
|
**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.
|
|
96
96
|
|
|
97
|
+
### Token Denomination (x100)
|
|
98
|
+
|
|
99
|
+
All confidential token amounts in this SDK use a fixed scale of 100. That means the SDK expects amounts in "token \* 100" units for deposit, transfer, and withdraw. When displaying balances, divide by 100.
|
|
100
|
+
|
|
101
|
+
- To deposit 0.1 tokens, send 10 units (0.1 \* 100).
|
|
102
|
+
- To display a balance, use $display = raw / 100$.
|
|
103
|
+
|
|
104
|
+
**Recommended helpers (consistent with examples):**
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
// Use 2 decimals to match x100 scaling
|
|
108
|
+
const amountToDeposit = ethers.parseUnits("0.1", 2); // 10
|
|
109
|
+
await client.confidentialDeposit(signer, tokenAddress, amountToDeposit);
|
|
110
|
+
|
|
111
|
+
const amountToTransfer = ethers.parseUnits("0.05", 2); // 5
|
|
112
|
+
await client.confidentialTransfer(
|
|
113
|
+
signer,
|
|
114
|
+
recipientAddress,
|
|
115
|
+
tokenAddress,
|
|
116
|
+
amountToTransfer,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const amountToWithdraw = ethers.parseUnits("0.02", 2); // 2
|
|
120
|
+
await client.withdraw(signer, tokenAddress, amountToWithdraw);
|
|
121
|
+
|
|
122
|
+
const balance = await client.getConfidentialBalance(
|
|
123
|
+
signer.address,
|
|
124
|
+
privateKey,
|
|
125
|
+
tokenAddress,
|
|
126
|
+
);
|
|
127
|
+
console.log("Balance:", ethers.formatUnits(balance.amount, 2));
|
|
128
|
+
```
|
|
129
|
+
|
|
97
130
|
### Key Functions
|
|
98
131
|
|
|
99
132
|
The following methods are the primary entry points for interacting with the confidential system.
|
|
100
133
|
|
|
101
|
-
#### `
|
|
134
|
+
#### `getAccountInfo(address)`
|
|
102
135
|
|
|
103
|
-
|
|
136
|
+
Fetches account core information from the contract.
|
|
104
137
|
|
|
105
138
|
- **Parameters**:
|
|
106
|
-
- `
|
|
107
|
-
- **Returns**:
|
|
139
|
+
- `address` (string): The account address.
|
|
140
|
+
- **Returns**: Contract account data (exists, finalized, pubkey, etc.).
|
|
108
141
|
|
|
109
142
|
#### `ensureAccount(signer, options)`
|
|
110
143
|
|
|
@@ -117,31 +150,32 @@ Initializes or retrieves the cryptographic keys associated with an account. This
|
|
|
117
150
|
- `maxAttempts` (number): Maximum attempts to check finalization. Default: `30`
|
|
118
151
|
- **Returns**: An object containing the user's private and public keys for the confidential system.
|
|
119
152
|
|
|
120
|
-
#### `
|
|
153
|
+
#### `getConfidentialBalance(address, privateKey, tokenAddress)`
|
|
121
154
|
|
|
122
|
-
Retrieves the decrypted
|
|
155
|
+
Retrieves the decrypted available and pending balances for a specific token, plus the total.
|
|
123
156
|
|
|
124
157
|
- **Parameters**:
|
|
125
158
|
- `address` (string): The account address.
|
|
126
159
|
- `privateKey` (string): The private key for decryption.
|
|
127
160
|
- `tokenAddress` (string): The token contract address.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
-
|
|
161
|
+
- **Returns**: An object containing:
|
|
162
|
+
- `amount` (number): The total (available + pending) in x100 units
|
|
163
|
+
- `available` (object): `{ amount, ciphertext }` in x100 units
|
|
164
|
+
- `pending` (object): `{ amount, ciphertext }` in x100 units
|
|
131
165
|
|
|
132
|
-
#### `
|
|
166
|
+
#### `confidentialDeposit(signer, tokenAddress, amount, options)`
|
|
133
167
|
|
|
134
168
|
Deposits a specified amount of ERC20 tokens into the confidential contract, converting them into a "pending" confidential balance.
|
|
135
169
|
|
|
136
170
|
- **Parameters**:
|
|
137
171
|
- `signer` (ethers.Signer): The transaction signer.
|
|
138
172
|
- `tokenAddress` (string): The contract address of the ERC20 token.
|
|
139
|
-
- `amount` (bigint | string | number): The amount to deposit
|
|
173
|
+
- `amount` (bigint | string | number): The amount to deposit in x100 units.
|
|
140
174
|
- `options` (object, optional):
|
|
141
175
|
- `waitForFinalization` (boolean): Wait for deposit finalization. Default: `true`
|
|
142
176
|
- **Returns**: A transaction receipt.
|
|
143
177
|
|
|
144
|
-
#### `
|
|
178
|
+
#### `confidentialTransfer(signer, recipientAddress, tokenAddress, amount, options)`
|
|
145
179
|
|
|
146
180
|
Executes a confidential transfer of tokens from the sender to a recipient. The amount and nature of the transfer are encrypted.
|
|
147
181
|
|
|
@@ -149,22 +183,12 @@ Executes a confidential transfer of tokens from the sender to a recipient. The a
|
|
|
149
183
|
- `signer` (ethers.Signer): The sender's signer.
|
|
150
184
|
- `recipientAddress` (string): The public address of the recipient.
|
|
151
185
|
- `tokenAddress` (string): The token contract address.
|
|
152
|
-
- `amount` (number): The amount to transfer.
|
|
186
|
+
- `amount` (number): The amount to transfer in x100 units.
|
|
153
187
|
- `options` (object, optional):
|
|
154
188
|
- `useOffchainVerify` (boolean): Use offchain verification. Default: `false`
|
|
155
189
|
- `waitForFinalization` (boolean): Wait for transfer finalization. Default: `true`
|
|
156
190
|
- **Returns**: A transaction receipt.
|
|
157
191
|
|
|
158
|
-
#### `applyPending(signer, options)`
|
|
159
|
-
|
|
160
|
-
Moves funds from the "pending" balance to the "available" balance. This is often necessary for the recipient to utilize received funds.
|
|
161
|
-
|
|
162
|
-
- **Parameters**:
|
|
163
|
-
- `signer` (ethers.Signer): The user's signer.
|
|
164
|
-
- `options` (object, optional):
|
|
165
|
-
- `waitForFinalization` (boolean): Wait for operation finalization. Default: `true`
|
|
166
|
-
- **Returns**: A transaction receipt.
|
|
167
|
-
|
|
168
192
|
#### `withdraw(signer, tokenAddress, amount, options)`
|
|
169
193
|
|
|
170
194
|
Withdraws funds from the confidential "available" balance back to the public layer (ERC20 tokens).
|
|
@@ -172,40 +196,12 @@ Withdraws funds from the confidential "available" balance back to the public lay
|
|
|
172
196
|
- **Parameters**:
|
|
173
197
|
- `signer` (ethers.Signer): The user's signer.
|
|
174
198
|
- `tokenAddress` (string): The token contract address.
|
|
175
|
-
- `amount` (number): The amount to withdraw.
|
|
199
|
+
- `amount` (number): The amount to withdraw in x100 units.
|
|
176
200
|
- `options` (object, optional):
|
|
177
201
|
- `useOffchainVerify` (boolean): Use offchain verification. Default: `false`
|
|
178
202
|
- `waitForFinalization` (boolean): Wait for withdrawal finalization. Default: `true`
|
|
179
203
|
- **Returns**: A transaction receipt.
|
|
180
204
|
|
|
181
|
-
#### `waitForPendingBalance(address, privateKey, tokenAddress, options)`
|
|
182
|
-
|
|
183
|
-
Polls for pending balance to appear after a transfer (typically after another user calls `applyPending`).
|
|
184
|
-
|
|
185
|
-
- **Parameters**:
|
|
186
|
-
- `address` (string): The account address.
|
|
187
|
-
- `privateKey` (string): The private key for decryption.
|
|
188
|
-
- `tokenAddress` (string): The token contract address.
|
|
189
|
-
- `options` (object, optional):
|
|
190
|
-
- `maxAttempts` (number): Maximum polling attempts. Default: `60`
|
|
191
|
-
- `intervalMs` (number): Polling interval in milliseconds. Default: `3000`
|
|
192
|
-
- **Returns**: An object containing `amount` and `ciphertext`.
|
|
193
|
-
|
|
194
|
-
#### `getFeeAmount()`
|
|
195
|
-
|
|
196
|
-
Retrieves the current fee amount required for confidential transfers on the network.
|
|
197
|
-
|
|
198
|
-
- **Returns**: The fee amount in wei (bigint).
|
|
199
|
-
|
|
200
|
-
#### `getTokenBalance(address, tokenAddress)`
|
|
201
|
-
|
|
202
|
-
Retrieves the public ERC20 token balance for an address (non-confidential).
|
|
203
|
-
|
|
204
|
-
- **Parameters**:
|
|
205
|
-
- `address` (string): The account address.
|
|
206
|
-
- `tokenAddress` (string): The token contract address.
|
|
207
|
-
- **Returns**: The token balance (bigint).
|
|
208
|
-
|
|
209
205
|
### Examples
|
|
210
206
|
|
|
211
207
|
For a complete implementation demonstrating the full lifecycle of a confidential transaction—from deposit to withdrawal—please refer to the `examples/complete-flow.js` file included in this repository.
|
|
@@ -221,7 +217,12 @@ The SDK provides descriptive error messages for common issues. Here are some typ
|
|
|
221
217
|
|
|
222
218
|
```javascript
|
|
223
219
|
try {
|
|
224
|
-
await client.
|
|
220
|
+
await client.confidentialTransfer(
|
|
221
|
+
signer,
|
|
222
|
+
recipientAddress,
|
|
223
|
+
tokenAddress,
|
|
224
|
+
amount,
|
|
225
|
+
);
|
|
225
226
|
} catch (error) {
|
|
226
227
|
if (error.message.includes("Insufficient balance")) {
|
|
227
228
|
console.error("Transfer amount exceeds available balance");
|
|
@@ -251,12 +252,12 @@ The following are estimated execution times for standard operations within the c
|
|
|
251
252
|
|
|
252
253
|
The following are estimated execution times for standard operations within the confidential flow. Please note that these durations may vary based on network congestion and client hardware performance.
|
|
253
254
|
|
|
254
|
-
| Operation
|
|
255
|
-
|
|
|
256
|
-
|
|
|
257
|
-
|
|
|
258
|
-
|
|
|
259
|
-
| Withdraw
|
|
255
|
+
| Operation | Avg Duration |
|
|
256
|
+
| :-------- | :----------- |
|
|
257
|
+
| Creation | 45s |
|
|
258
|
+
| Deposit | 63s |
|
|
259
|
+
| Transfer | 58s |
|
|
260
|
+
| Withdraw | 58s |
|
|
260
261
|
|
|
261
262
|
## Security Considerations
|
|
262
263
|
|
|
@@ -283,9 +284,10 @@ When using the StableTrust SDK, follow these best practices to ensure the securi
|
|
|
283
284
|
- Allow sufficient time for account finalization before proceeding with operations
|
|
284
285
|
|
|
285
286
|
5. **Balance Verification**
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
|
|
288
|
+
- Check available balance before initiating transfers (values are in x100 units)
|
|
289
|
+
- Be aware of transaction fees that may vary by network
|
|
290
|
+
- On Tempo chain, ensure sufficient PathUSD balance for fee payment
|
|
289
291
|
|
|
290
292
|
6. **Error Handling**
|
|
291
293
|
- Implement comprehensive error handling for all SDK operations
|
|
@@ -11,18 +11,18 @@ dotenv.config();
|
|
|
11
11
|
* https://docs.fairblock.network/docs/confidential_transfers/technical_overview
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
// Currently configured for
|
|
14
|
+
// Currently configured for Stable Testnet confidential mirror contract.
|
|
15
15
|
// You can deploy your own confidential contract on any EVM network and use that.
|
|
16
16
|
const CONTRACT_ADDRESS =
|
|
17
|
-
process.env.CONTRACT_ADDRESS || "
|
|
17
|
+
process.env.CONTRACT_ADDRESS || "0x29E4fd434758b1677c10854Fa81C2fc496D76E62";
|
|
18
18
|
// Standard ERC20 token contract. Any ERC20 on this chain ID can be used.
|
|
19
19
|
const TOKEN_ADDRESS =
|
|
20
|
-
process.env.TOKEN_ADDRESS || "
|
|
20
|
+
process.env.TOKEN_ADDRESS || "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9";
|
|
21
21
|
const RPC_URL =
|
|
22
|
-
process.env.ETHEREUM_RPC_URL || "https://
|
|
22
|
+
process.env.ETHEREUM_RPC_URL || "https://rpc.testnet.stable.xyz";
|
|
23
23
|
const EXPLORER_URL =
|
|
24
|
-
process.env.EXPLORER_URL || "https://
|
|
25
|
-
const CHAIN_ID = process.env.CHAIN_ID ||
|
|
24
|
+
process.env.EXPLORER_URL || "https://testnet.stablescan.xyz/tx/";
|
|
25
|
+
const CHAIN_ID = process.env.CHAIN_ID || 2201;
|
|
26
26
|
1;
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -64,141 +64,109 @@ async function main() {
|
|
|
64
64
|
const recipientKeys = await client.ensureAccount(recipient);
|
|
65
65
|
|
|
66
66
|
// 1. DEPOSIT PHASE
|
|
67
|
-
const depositAmount = ethers.parseUnits("0.1",
|
|
68
|
-
const
|
|
67
|
+
const depositAmount = ethers.parseUnits("0.1", 2);
|
|
68
|
+
const senderConfidentialBalanceBefore = await client.getConfidentialBalance(
|
|
69
69
|
sender.address,
|
|
70
70
|
senderKeys.privateKey,
|
|
71
71
|
TOKEN_ADDRESS,
|
|
72
|
-
{ type: "available" },
|
|
73
72
|
);
|
|
73
|
+
|
|
74
74
|
console.log(
|
|
75
|
-
"Sender
|
|
76
|
-
ethers.formatUnits(
|
|
75
|
+
"Sender Confidential Balance (Pre-Deposit):",
|
|
76
|
+
ethers.formatUnits(senderConfidentialBalanceBefore.amount, 2),
|
|
77
77
|
);
|
|
78
78
|
|
|
79
|
+
console.log("Depositing 0.1 tokens into confidential contract...");
|
|
80
|
+
|
|
79
81
|
const depRes = await trackPerformance("DEPOSIT_TOKENS", () =>
|
|
80
|
-
client.
|
|
82
|
+
client.confidentialDeposit(sender, TOKEN_ADDRESS, depositAmount),
|
|
81
83
|
);
|
|
82
84
|
// Fixed hash reference: checking for result.transactionHash or result.hash
|
|
83
85
|
const depHash = depRes.result.hash;
|
|
84
86
|
console.log(`Transaction Hash: ${depHash}`);
|
|
85
87
|
console.log(`View Transaction: ${EXPLORER_URL}${depHash}`);
|
|
86
88
|
|
|
87
|
-
const
|
|
89
|
+
const senderConfidentialBalanceAfterDep = await client.getConfidentialBalance(
|
|
88
90
|
sender.address,
|
|
89
91
|
senderKeys.privateKey,
|
|
90
92
|
TOKEN_ADDRESS,
|
|
91
|
-
{ type: "available" },
|
|
92
93
|
);
|
|
93
94
|
console.log(
|
|
94
|
-
"Sender
|
|
95
|
-
ethers.formatUnits(
|
|
96
|
-
"\n",
|
|
95
|
+
"Sender Confidential Balance (Post-Deposit):",
|
|
96
|
+
ethers.formatUnits(senderConfidentialBalanceAfterDep.amount, 2),
|
|
97
97
|
);
|
|
98
98
|
|
|
99
99
|
// 2. TRANSFER PHASE
|
|
100
|
-
const transferAmount = ethers.parseUnits("0.05",
|
|
101
|
-
const
|
|
100
|
+
const transferAmount = ethers.parseUnits("0.05", 2);
|
|
101
|
+
const senderConfidentialBalanceBeforeTx = await client.getConfidentialBalance(
|
|
102
102
|
sender.address,
|
|
103
103
|
senderKeys.privateKey,
|
|
104
104
|
TOKEN_ADDRESS,
|
|
105
|
-
{ type: "available" },
|
|
106
|
-
);
|
|
107
|
-
const recipientPendBeforeTx = await client.getBalance(
|
|
108
|
-
recipient.address,
|
|
109
|
-
recipientKeys.privateKey,
|
|
110
|
-
TOKEN_ADDRESS,
|
|
111
|
-
{ type: "pending" },
|
|
112
105
|
);
|
|
113
106
|
|
|
107
|
+
const recipientConfidentialBalanceBeforeTx =
|
|
108
|
+
await client.getConfidentialBalance(
|
|
109
|
+
recipient.address,
|
|
110
|
+
recipientKeys.privateKey,
|
|
111
|
+
TOKEN_ADDRESS,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
114
|
console.log(
|
|
115
|
-
"Sender
|
|
116
|
-
ethers.formatUnits(
|
|
115
|
+
"Sender Confidential Balance (Pre-Transfer):",
|
|
116
|
+
ethers.formatUnits(senderConfidentialBalanceBeforeTx.amount, 2),
|
|
117
117
|
);
|
|
118
118
|
console.log(
|
|
119
|
-
"Recipient
|
|
120
|
-
ethers.formatUnits(
|
|
119
|
+
"Recipient Confidential Balance (Pre-Transfer):",
|
|
120
|
+
ethers.formatUnits(recipientConfidentialBalanceBeforeTx.amount, 2),
|
|
121
121
|
);
|
|
122
122
|
|
|
123
|
+
console.log("Transferring 0.05 tokens confidentially to recipient...");
|
|
124
|
+
|
|
123
125
|
// FIXED: Ensured all arguments are explicitly passed in the arrow function
|
|
124
126
|
const txRes = await trackPerformance("CONFIDENTIAL_TRANSFER", () =>
|
|
125
|
-
client.
|
|
127
|
+
client.confidentialTransfer(
|
|
128
|
+
sender,
|
|
129
|
+
recipient.address,
|
|
130
|
+
TOKEN_ADDRESS,
|
|
131
|
+
transferAmount,
|
|
132
|
+
),
|
|
126
133
|
);
|
|
127
134
|
|
|
128
135
|
const txHash = txRes.result.hash;
|
|
129
136
|
console.log(
|
|
130
|
-
"Status:
|
|
137
|
+
"Status:Confidential Transfer is completed. Transfer amount is hidden on-chain.",
|
|
131
138
|
);
|
|
132
139
|
console.log(`Transaction Hash: ${txHash}`);
|
|
133
140
|
console.log(`View Transaction: ${EXPLORER_URL}${txHash}`);
|
|
134
141
|
|
|
135
|
-
const
|
|
142
|
+
const senderConfidentialBalanceAfterTx = await client.getConfidentialBalance(
|
|
136
143
|
sender.address,
|
|
137
144
|
senderKeys.privateKey,
|
|
138
145
|
TOKEN_ADDRESS,
|
|
139
|
-
{ type: "available" },
|
|
140
|
-
);
|
|
141
|
-
const recipientPendAfterTx = await client.getBalance(
|
|
142
|
-
recipient.address,
|
|
143
|
-
recipientKeys.privateKey,
|
|
144
|
-
TOKEN_ADDRESS,
|
|
145
|
-
{ type: "pending" },
|
|
146
146
|
);
|
|
147
147
|
|
|
148
|
+
const recipientConfidentialBalanceAfterTx =
|
|
149
|
+
await client.getConfidentialBalance(
|
|
150
|
+
recipient.address,
|
|
151
|
+
recipientKeys.privateKey,
|
|
152
|
+
TOKEN_ADDRESS,
|
|
153
|
+
);
|
|
154
|
+
|
|
148
155
|
console.log(
|
|
149
|
-
"Sender
|
|
150
|
-
ethers.formatUnits(
|
|
156
|
+
"Sender Confidential Balance (Post-Transfer):",
|
|
157
|
+
ethers.formatUnits(senderConfidentialBalanceAfterTx.amount, 2),
|
|
151
158
|
);
|
|
152
159
|
console.log(
|
|
153
|
-
"Recipient
|
|
154
|
-
ethers.formatUnits(
|
|
160
|
+
"Recipient Confidential Balance (Post-Transfer):",
|
|
161
|
+
ethers.formatUnits(recipientConfidentialBalanceAfterTx.amount, 2),
|
|
155
162
|
"\n",
|
|
156
163
|
);
|
|
157
164
|
|
|
158
|
-
// 3.
|
|
159
|
-
const
|
|
160
|
-
recipient.address,
|
|
161
|
-
recipientKeys.privateKey,
|
|
162
|
-
TOKEN_ADDRESS,
|
|
163
|
-
{ type: "available" },
|
|
164
|
-
);
|
|
165
|
+
// 3. WITHDRAW PHASE
|
|
166
|
+
const withdrawAmount = ethers.parseUnits("0.05", 2);
|
|
165
167
|
console.log(
|
|
166
|
-
"
|
|
167
|
-
ethers.formatUnits(recipientAvailBeforeApply.amount, 6),
|
|
168
|
+
"Withdrawing 0.05 tokens from confidential contract to recipient's public balance...",
|
|
168
169
|
);
|
|
169
|
-
|
|
170
|
-
const applyRes = await trackPerformance("APPLY_PENDING", () =>
|
|
171
|
-
client.applyPending(recipient),
|
|
172
|
-
);
|
|
173
|
-
const applyHash = applyRes.result.hash;
|
|
174
|
-
console.log(`Transaction Hash: ${applyHash}`);
|
|
175
|
-
console.log(`View Transaction: ${EXPLORER_URL}${applyHash}`);
|
|
176
|
-
|
|
177
|
-
const recipientPendAfterApply = await client.getBalance(
|
|
178
|
-
recipient.address,
|
|
179
|
-
recipientKeys.privateKey,
|
|
180
|
-
TOKEN_ADDRESS,
|
|
181
|
-
{ type: "pending" },
|
|
182
|
-
);
|
|
183
|
-
const recipientAvailAfterApply = await client.getBalance(
|
|
184
|
-
recipient.address,
|
|
185
|
-
recipientKeys.privateKey,
|
|
186
|
-
TOKEN_ADDRESS,
|
|
187
|
-
{ type: "available" },
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
console.log(
|
|
191
|
-
"Recipient Pending (Post-Apply):",
|
|
192
|
-
ethers.formatUnits(recipientPendAfterApply.amount, 6),
|
|
193
|
-
);
|
|
194
|
-
console.log(
|
|
195
|
-
"Recipient Available (Post-Apply):",
|
|
196
|
-
ethers.formatUnits(recipientAvailAfterApply.amount, 6),
|
|
197
|
-
"\n",
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
// 4. WITHDRAW PHASE
|
|
201
|
-
const withdrawAmount = ethers.parseUnits("0.05", 6);
|
|
202
170
|
const withdrawRes = await trackPerformance("WITHDRAW_TOKENS", () =>
|
|
203
171
|
client.withdraw(recipient, TOKEN_ADDRESS, withdrawAmount),
|
|
204
172
|
);
|
|
@@ -206,15 +174,16 @@ async function main() {
|
|
|
206
174
|
console.log(`Transaction Hash: ${withdrawHash}`);
|
|
207
175
|
console.log(`View Transaction: ${EXPLORER_URL}${withdrawHash}`);
|
|
208
176
|
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
177
|
+
const recipientConfidentialBalanceAfterWithdraw =
|
|
178
|
+
await client.getConfidentialBalance(
|
|
179
|
+
recipient.address,
|
|
180
|
+
recipientKeys.privateKey,
|
|
181
|
+
TOKEN_ADDRESS,
|
|
182
|
+
);
|
|
183
|
+
|
|
215
184
|
console.log(
|
|
216
|
-
"Recipient
|
|
217
|
-
ethers.formatUnits(
|
|
185
|
+
"Recipient Confidential Balance (Final):",
|
|
186
|
+
ethers.formatUnits(recipientConfidentialBalanceAfterWithdraw.amount, 2),
|
|
218
187
|
);
|
|
219
188
|
|
|
220
189
|
console.log("\n=== Complete Flow Execution Finished ===");
|
|
@@ -3,15 +3,15 @@ import dotenv from "dotenv";
|
|
|
3
3
|
import { ConfidentialTransferClient } from "@fairblock/stabletrust";
|
|
4
4
|
dotenv.config();
|
|
5
5
|
const RPC_URL =
|
|
6
|
-
process.env.
|
|
6
|
+
process.env.ETHEREUM_RPC_URL || "https://rpc.testnet.stable.xyz";
|
|
7
7
|
const EXPLORER_URL =
|
|
8
|
-
process.env.EXPLORER_URL || "https://
|
|
8
|
+
process.env.EXPLORER_URL || "https://testnet.stablescan.xyz/tx/";
|
|
9
9
|
async function minimalFlow() {
|
|
10
10
|
// 1. Setup Client & Wallets
|
|
11
11
|
const client = new ConfidentialTransferClient(
|
|
12
12
|
RPC_URL,
|
|
13
|
-
"
|
|
14
|
-
|
|
13
|
+
"0x29E4fd434758b1677c10854Fa81C2fc496D76E62",
|
|
14
|
+
2201,
|
|
15
15
|
);
|
|
16
16
|
|
|
17
17
|
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
|
@@ -25,20 +25,22 @@ async function minimalFlow() {
|
|
|
25
25
|
await client.ensureAccount(sender);
|
|
26
26
|
await client.ensureAccount(recipient);
|
|
27
27
|
|
|
28
|
-
const TOKEN = "
|
|
28
|
+
const TOKEN = "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9";
|
|
29
29
|
const amount = ethers.parseUnits("0.001", 6);
|
|
30
30
|
let res;
|
|
31
31
|
// 3. DEPOSIT: Move public ERC20 into the confidential contract
|
|
32
|
-
res = await client.
|
|
32
|
+
res = await client.confidentialDeposit(sender, TOKEN, amount);
|
|
33
33
|
console.log("Deposit TX Hash:", EXPLORER_URL + res.hash);
|
|
34
34
|
// 4. TRANSFER: Privacy-preserving transfer (On-chain amount is hidden)
|
|
35
35
|
// This moves funds from Sender's 'Available' to Recipient's 'Pending' balance
|
|
36
|
-
res = await client.
|
|
36
|
+
res = await client.confidentialTransfer(
|
|
37
|
+
sender,
|
|
38
|
+
recipient.address,
|
|
39
|
+
TOKEN,
|
|
40
|
+
amount / 2n,
|
|
41
|
+
);
|
|
37
42
|
console.log("Transfer TX Hash:", EXPLORER_URL + res.hash);
|
|
38
|
-
// 5.
|
|
39
|
-
res = await client.applyPending(recipient);
|
|
40
|
-
console.log("Settle TX Hash:", EXPLORER_URL + res.hash);
|
|
41
|
-
// 6. WITHDRAW: Convert confidential balance back to public ERC20
|
|
43
|
+
// 5. WITHDRAW: Convert confidential balance back to public ERC20
|
|
42
44
|
res = await client.withdraw(recipient, TOKEN, amount / 4n);
|
|
43
45
|
console.log("Withdraw TX Hash:", EXPLORER_URL + res.hash);
|
|
44
46
|
console.log("Confidential flow complete.");
|
package/package.json
CHANGED