@fairblock/stabletrust 1.0.0 → 1.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/complete-flow.js +225 -0
- package/examples/simple-snippets.js +49 -0
- package/package.json +6 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { ethers } from "ethers";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
import { ConfidentialTransferClient } from "@fairblock/stabletrust";
|
|
4
|
+
|
|
5
|
+
dotenv.config();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ARCHITECTURE OVERVIEW:
|
|
9
|
+
* For deep dive into the underlying architecture and the separation
|
|
10
|
+
* of Pending and Available balances, visit:
|
|
11
|
+
* https://docs.fairblock.network/docs/confidential_transfers/technical_overview
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Currently configured for Arbitrum Sepolia confidential mirror contract.
|
|
15
|
+
// You can deploy your own confidential contract on any EVM network and use that.
|
|
16
|
+
const CONTRACT_ADDRESS =
|
|
17
|
+
process.env.CONTRACT_ADDRESS || "0x5acE788EF0C9f7f902642001d639AD155fF29A6C";
|
|
18
|
+
// Standard ERC20 token contract. Any ERC20 on this chain ID can be used.
|
|
19
|
+
const TOKEN_ADDRESS =
|
|
20
|
+
process.env.TOKEN_ADDRESS || "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d";
|
|
21
|
+
const RPC_URL =
|
|
22
|
+
process.env.ARBITRUM_RPC_URL || "https://sepolia-rollup.arbitrum.io/rpc";
|
|
23
|
+
const EXPLORER_URL =
|
|
24
|
+
process.env.EXPLORER_URL || "https://sepolia.arbiscan.io/tx/";
|
|
25
|
+
const CHAIN_ID = process.env.CHAIN_ID || 421614;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Performance Utility: Tracks execution time and provides timestamps
|
|
29
|
+
*/
|
|
30
|
+
async function trackPerformance(actionName, action) {
|
|
31
|
+
const timestamp = new Date().toISOString();
|
|
32
|
+
const start = performance.now();
|
|
33
|
+
const result = await action();
|
|
34
|
+
const end = performance.now();
|
|
35
|
+
const duration = ((end - start) / 1000).toFixed(3);
|
|
36
|
+
|
|
37
|
+
console.log(`Action: ${actionName}`);
|
|
38
|
+
console.log(`Timestamp: ${timestamp}`);
|
|
39
|
+
console.log(`Duration: ${duration}s`);
|
|
40
|
+
return { result, duration };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function main() {
|
|
44
|
+
console.log("=== Starting Confidential Flow Performance Test ===\n");
|
|
45
|
+
|
|
46
|
+
const client = new ConfidentialTransferClient(
|
|
47
|
+
RPC_URL,
|
|
48
|
+
CONTRACT_ADDRESS,
|
|
49
|
+
CHAIN_ID,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
|
53
|
+
const sender = new ethers.Wallet(process.env.SENDER_PRIVATE_KEY, provider);
|
|
54
|
+
const recipient = new ethers.Wallet(
|
|
55
|
+
process.env.RECIPIENT_PRIVATE_KEY,
|
|
56
|
+
provider,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
console.log("Sender Address:", sender.address);
|
|
60
|
+
console.log("Recipient Address:", recipient.address);
|
|
61
|
+
|
|
62
|
+
const senderKeys = await client.ensureAccount(sender);
|
|
63
|
+
const recipientKeys = await client.ensureAccount(recipient);
|
|
64
|
+
|
|
65
|
+
// 1. DEPOSIT PHASE
|
|
66
|
+
const depositAmount = ethers.parseUnits("0.1", 6);
|
|
67
|
+
const senderAvailBeforeDep = await client.getBalance(
|
|
68
|
+
sender.address,
|
|
69
|
+
senderKeys.privateKey,
|
|
70
|
+
TOKEN_ADDRESS,
|
|
71
|
+
{ type: "available" },
|
|
72
|
+
);
|
|
73
|
+
console.log(
|
|
74
|
+
"Sender Available (Pre-Deposit):",
|
|
75
|
+
ethers.formatUnits(senderAvailBeforeDep.amount, 6),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const depRes = await trackPerformance("DEPOSIT_TOKENS", () =>
|
|
79
|
+
client.deposit(sender, TOKEN_ADDRESS, depositAmount),
|
|
80
|
+
);
|
|
81
|
+
// Fixed hash reference: checking for result.transactionHash or result.hash
|
|
82
|
+
const depHash = depRes.result.hash;
|
|
83
|
+
console.log(`Transaction Hash: ${depHash}`);
|
|
84
|
+
console.log(`View Transaction: ${EXPLORER_URL}${depHash}`);
|
|
85
|
+
|
|
86
|
+
const senderAvailAfterDep = await client.getBalance(
|
|
87
|
+
sender.address,
|
|
88
|
+
senderKeys.privateKey,
|
|
89
|
+
TOKEN_ADDRESS,
|
|
90
|
+
{ type: "available" },
|
|
91
|
+
);
|
|
92
|
+
console.log(
|
|
93
|
+
"Sender Available (Post-Deposit):",
|
|
94
|
+
ethers.formatUnits(senderAvailAfterDep.amount, 6),
|
|
95
|
+
"\n",
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// 2. TRANSFER PHASE
|
|
99
|
+
const transferAmount = ethers.parseUnits("0.05", 6);
|
|
100
|
+
const senderAvailBeforeTx = await client.getBalance(
|
|
101
|
+
sender.address,
|
|
102
|
+
senderKeys.privateKey,
|
|
103
|
+
TOKEN_ADDRESS,
|
|
104
|
+
{ type: "available" },
|
|
105
|
+
);
|
|
106
|
+
const recipientPendBeforeTx = await client.getBalance(
|
|
107
|
+
recipient.address,
|
|
108
|
+
recipientKeys.privateKey,
|
|
109
|
+
TOKEN_ADDRESS,
|
|
110
|
+
{ type: "pending" },
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
console.log(
|
|
114
|
+
"Sender Available (Pre-Transfer):",
|
|
115
|
+
ethers.formatUnits(senderAvailBeforeTx.amount, 6),
|
|
116
|
+
);
|
|
117
|
+
console.log(
|
|
118
|
+
"Recipient Pending (Pre-Transfer):",
|
|
119
|
+
ethers.formatUnits(recipientPendBeforeTx.amount, 6),
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// FIXED: Ensured all arguments are explicitly passed in the arrow function
|
|
123
|
+
const txRes = await trackPerformance("CONFIDENTIAL_TRANSFER", () =>
|
|
124
|
+
client.transfer(sender, recipient.address, TOKEN_ADDRESS, transferAmount),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const txHash = txRes.result.hash;
|
|
128
|
+
console.log(
|
|
129
|
+
"Status: Privacy shielding active. Transfer amount is hidden on-chain.",
|
|
130
|
+
);
|
|
131
|
+
console.log(`Transaction Hash: ${txHash}`);
|
|
132
|
+
console.log(`View Transaction: ${EXPLORER_URL}${txHash}`);
|
|
133
|
+
|
|
134
|
+
const senderAvailAfterTx = await client.getBalance(
|
|
135
|
+
sender.address,
|
|
136
|
+
senderKeys.privateKey,
|
|
137
|
+
TOKEN_ADDRESS,
|
|
138
|
+
{ type: "available" },
|
|
139
|
+
);
|
|
140
|
+
const recipientPendAfterTx = await client.getBalance(
|
|
141
|
+
recipient.address,
|
|
142
|
+
recipientKeys.privateKey,
|
|
143
|
+
TOKEN_ADDRESS,
|
|
144
|
+
{ type: "pending" },
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
console.log(
|
|
148
|
+
"Sender Available (Post-Transfer):",
|
|
149
|
+
ethers.formatUnits(senderAvailAfterTx.amount, 6),
|
|
150
|
+
);
|
|
151
|
+
console.log(
|
|
152
|
+
"Recipient Pending (Post-Transfer):",
|
|
153
|
+
ethers.formatUnits(recipientPendAfterTx.amount, 6),
|
|
154
|
+
"\n",
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// 3. APPLY PENDING PHASE
|
|
158
|
+
const recipientAvailBeforeApply = await client.getBalance(
|
|
159
|
+
recipient.address,
|
|
160
|
+
recipientKeys.privateKey,
|
|
161
|
+
TOKEN_ADDRESS,
|
|
162
|
+
{ type: "available" },
|
|
163
|
+
);
|
|
164
|
+
console.log(
|
|
165
|
+
"Recipient Available (Pre-Apply):",
|
|
166
|
+
ethers.formatUnits(recipientAvailBeforeApply.amount, 6),
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const applyRes = await trackPerformance("APPLY_PENDING", () =>
|
|
170
|
+
client.applyPending(recipient),
|
|
171
|
+
);
|
|
172
|
+
const applyHash = applyRes.result.hash;
|
|
173
|
+
console.log(`Transaction Hash: ${applyHash}`);
|
|
174
|
+
console.log(`View Transaction: ${EXPLORER_URL}${applyHash}`);
|
|
175
|
+
|
|
176
|
+
const recipientPendAfterApply = await client.getBalance(
|
|
177
|
+
recipient.address,
|
|
178
|
+
recipientKeys.privateKey,
|
|
179
|
+
TOKEN_ADDRESS,
|
|
180
|
+
{ type: "pending" },
|
|
181
|
+
);
|
|
182
|
+
const recipientAvailAfterApply = await client.getBalance(
|
|
183
|
+
recipient.address,
|
|
184
|
+
recipientKeys.privateKey,
|
|
185
|
+
TOKEN_ADDRESS,
|
|
186
|
+
{ type: "available" },
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
console.log(
|
|
190
|
+
"Recipient Pending (Post-Apply):",
|
|
191
|
+
ethers.formatUnits(recipientPendAfterApply.amount, 6),
|
|
192
|
+
);
|
|
193
|
+
console.log(
|
|
194
|
+
"Recipient Available (Post-Apply):",
|
|
195
|
+
ethers.formatUnits(recipientAvailAfterApply.amount, 6),
|
|
196
|
+
"\n",
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
// 4. WITHDRAW PHASE
|
|
200
|
+
const withdrawAmount = ethers.parseUnits("0.05", 6);
|
|
201
|
+
const withdrawRes = await trackPerformance("WITHDRAW_TOKENS", () =>
|
|
202
|
+
client.withdraw(recipient, TOKEN_ADDRESS, withdrawAmount),
|
|
203
|
+
);
|
|
204
|
+
const withdrawHash = withdrawRes.result.hash;
|
|
205
|
+
console.log(`Transaction Hash: ${withdrawHash}`);
|
|
206
|
+
console.log(`View Transaction: ${EXPLORER_URL}${withdrawHash}`);
|
|
207
|
+
|
|
208
|
+
const recipientAvailAfterWithdraw = await client.getBalance(
|
|
209
|
+
recipient.address,
|
|
210
|
+
recipientKeys.privateKey,
|
|
211
|
+
TOKEN_ADDRESS,
|
|
212
|
+
{ type: "available" },
|
|
213
|
+
);
|
|
214
|
+
console.log(
|
|
215
|
+
"Recipient Available (Final):",
|
|
216
|
+
ethers.formatUnits(recipientAvailAfterWithdraw.amount, 6),
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
console.log("\n=== Complete Flow Execution Finished ===");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
main().catch((error) => {
|
|
223
|
+
console.error("Execution Error:", error);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ethers } from "ethers";
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
|
+
import { ConfidentialTransferClient } from "@fairblock/stabletrust";
|
|
4
|
+
dotenv.config();
|
|
5
|
+
const RPC_URL =
|
|
6
|
+
process.env.ARBITRUM_RPC_URL || "https://sepolia-rollup.arbitrum.io/rpc";
|
|
7
|
+
const EXPLORER_URL =
|
|
8
|
+
process.env.EXPLORER_URL || "https://sepolia.arbiscan.io/tx/";
|
|
9
|
+
async function minimalFlow() {
|
|
10
|
+
// 1. Setup Client & Wallets
|
|
11
|
+
const client = new ConfidentialTransferClient(
|
|
12
|
+
RPC_URL,
|
|
13
|
+
"0x30bAc8a17DCACbA7f70F305f4ad908C9fd6d3E2E",
|
|
14
|
+
421614,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const provider = new ethers.JsonRpcProvider(RPC_URL);
|
|
18
|
+
const sender = new ethers.Wallet(process.env.SENDER_PRIVATE_KEY, provider);
|
|
19
|
+
const recipient = new ethers.Wallet(
|
|
20
|
+
process.env.RECIPIENT_PRIVATE_KEY,
|
|
21
|
+
provider,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// 2. Initialize Confidential Accounts (View Keys)
|
|
25
|
+
await client.ensureAccount(sender);
|
|
26
|
+
await client.ensureAccount(recipient);
|
|
27
|
+
|
|
28
|
+
const TOKEN = "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d";
|
|
29
|
+
const amount = ethers.parseUnits("0.001", 6);
|
|
30
|
+
let res;
|
|
31
|
+
// 3. DEPOSIT: Move public ERC20 into the confidential contract
|
|
32
|
+
res = await client.deposit(sender, TOKEN, amount);
|
|
33
|
+
console.log("Deposit TX Hash:", EXPLORER_URL + res.hash);
|
|
34
|
+
// 4. TRANSFER: Privacy-preserving transfer (On-chain amount is hidden)
|
|
35
|
+
// This moves funds from Sender's 'Available' to Recipient's 'Pending' balance
|
|
36
|
+
res = await client.transfer(sender, recipient.address, TOKEN, amount / 2n);
|
|
37
|
+
console.log("Transfer TX Hash:", EXPLORER_URL + res.hash);
|
|
38
|
+
// 5. SETTLE: Recipient claims pending transfers into their available balance
|
|
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
|
|
42
|
+
res = await client.withdraw(recipient, TOKEN, amount / 4n);
|
|
43
|
+
console.log("Withdraw TX Hash:", EXPLORER_URL + res.hash);
|
|
44
|
+
console.log("Confidential flow complete.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
minimalFlow().catch((error) => {
|
|
48
|
+
console.error("Error in minimal confidential flow:", error);
|
|
49
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fairblock/stabletrust",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.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",
|
|
@@ -15,9 +15,14 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"src/",
|
|
17
17
|
"pkg/",
|
|
18
|
+
"examples/",
|
|
18
19
|
"README.md",
|
|
19
20
|
"CHANGELOG.md"
|
|
20
21
|
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/Fairblock/stabletrust-sdk"
|
|
25
|
+
},
|
|
21
26
|
"scripts": {
|
|
22
27
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
23
28
|
},
|