@fairblock/stabletrust 1.0.9 → 1.0.10

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 CHANGED
@@ -36,14 +36,14 @@ yarn add @fairblock/stabletrust
36
36
 
37
37
  The following contract addresses are available for confidential transfers on testnet networks. These are test deployments and should not be used with mainnet assets:
38
38
 
39
- | Network | Chain ID | Contract Address |
40
- | :------- | :------- | :------------------------------------------- |
41
- | Stable | 2201 | `0x29E4fd434758b1677c10854Fa81C2fc496D76E62` |
42
- | Arc | 1244 | `0x1Bf79BF5A32D6f3cdce3fe1A93c3fB222Bc93bb3` |
43
- | Base | 84532 | `0x73D2bc5B5c7aF5C3726E7bEf0BD8b4931923fdA9` |
44
- | Ethereum | 11155111 | `0xD765Dff7D734ABE09f88991A46BAb73ACa8910EF` |
45
- | Arbitrum | 421614 | `0xDC7Df05C2ce67881CDbF9A1af0F4C5d8C94c8A03` |
46
- | Tempo | 42431 | `0xB7bdce025c8a25e341Cb55795f8ba865AB3e392C` |
39
+ | Network(Testnet) | Chain ID | Contract Address |
40
+ | :--------------- | :------- | :------------------------------------------- |
41
+ | Stable | 2201 | `0x29E4fd434758b1677c10854Fa81C2fc496D76E62` |
42
+ | Arc | 1244 | `0xf085e801a6FD9d03b09566a738734B7e2Bb065De` |
43
+ | Base | 84532 | `0x6FE45A71F5232a4E5e583Ae31A538360fB1e6aDb` |
44
+ | Ethereum | 11155111 | `0x81a2c161c0327464430658516eE74A669feFC7bC` |
45
+ | Arbitrum | 421614 | `0xa59462200F6E438c538b914eB5F980B3Fa723aA0` |
46
+ | Tempo | 42431 | `0xB7bdce025c8a25e341Cb55795f8ba865AB3e392C` |
47
47
 
48
48
  ## Usage
49
49
 
@@ -57,37 +57,40 @@ Import and initialize the client with your network configuration.
57
57
  import { ConfidentialTransferClient } from "@fairblock/stabletrust";
58
58
  import { ethers } from "ethers";
59
59
 
60
- // Configuration for Arbitrum (example)
60
+ // Configuration for Base Sepolia (uses SDK default StableTrust contract for chainId 84532)
61
61
  const client = new ConfidentialTransferClient(
62
- "https://arb1.arbitrum.io/rpc",
63
- "0x5acE788EF0C9f7f902642001d639AD155fF29A6C",
64
- 42161,
62
+ "https://sepolia.base.org",
63
+ 84532,
64
+ );
65
+ ```
66
+
67
+ If you are using a custom deployment, you can still pass an explicit contract address:
68
+
69
+ ```javascript
70
+ const customClient = new ConfidentialTransferClient(
71
+ "https://sepolia.base.org",
72
+ "0xYourCustomStableTrustContract",
73
+ 84532,
65
74
  );
66
75
  ```
67
76
 
68
77
  #### Network Configuration Examples
69
78
 
70
- For different networks, use the following configurations:
79
+ For testnet networks listed above, use the following configurations:
71
80
 
72
81
  ```javascript
73
- // Base
74
- const baseClient = new ConfidentialTransferClient(
75
- "https://mainnet.base.org",
76
- "0x05ad3FF447930ad5B4085C07B4Ef9b10Aa0a58F2",
77
- 8453,
82
+ // Stable testnet
83
+ const stableClient = new ConfidentialTransferClient(
84
+ "https://rpc.testnet.stable.xyz",
85
+ 2201,
78
86
  );
79
87
 
80
- // Ethereum Mainnet
81
- const ethClient = new ConfidentialTransferClient(
82
- "https://eth.public.netzach.io",
83
- "0x7B5A0060dE15a1AA1b9712A0146145E9D01A1acA",
84
- 1,
85
- );
88
+ // Arc testnet
89
+ const arcClient = new ConfidentialTransferClient("https://rpc.arc.xyz", 1244);
86
90
 
87
91
  // Tempo (Stablecoin chain with special fee handling)
88
92
  const tempoClient = new ConfidentialTransferClient(
89
93
  "https://tempo-rpc.example.com",
90
- "0x17176c409B66bb03d102215eeEdb34259Db0F5AD",
91
94
  42431,
92
95
  );
93
96
  ```
@@ -11,8 +11,7 @@ dotenv.config();
11
11
  * https://docs.fairblock.network/docs/confidential_transfers/technical_overview
12
12
  */
13
13
 
14
- // Currently configured for Stable Testnet confidential mirror contract.
15
- // You can deploy your own confidential contract on any EVM network and use that.
14
+ // Optional override for custom confidential contract deployments.
16
15
  const CONTRACT_ADDRESS =
17
16
  process.env.CONTRACT_ADDRESS || "0x29E4fd434758b1677c10854Fa81C2fc496D76E62";
18
17
  // Standard ERC20 token contract. Any ERC20 on this chain ID can be used.
@@ -23,7 +22,6 @@ const RPC_URL =
23
22
  const EXPLORER_URL =
24
23
  process.env.EXPLORER_URL || "https://testnet.stablescan.xyz/tx/";
25
24
  const CHAIN_ID = process.env.CHAIN_ID || 2201;
26
- 1;
27
25
 
28
26
  /**
29
27
  * Performance Utility: Tracks execution time and provides timestamps
@@ -47,7 +45,7 @@ async function main() {
47
45
  const client = new ConfidentialTransferClient(
48
46
  RPC_URL,
49
47
  CONTRACT_ADDRESS,
50
- CHAIN_ID,
48
+ Number(CHAIN_ID),
51
49
  );
52
50
 
53
51
  const provider = new ethers.JsonRpcProvider(RPC_URL);
@@ -7,11 +7,7 @@ const EXPLORER_URL =
7
7
  process.env.EXPLORER_URL || "https://testnet.stablescan.xyz/tx/";
8
8
  async function minimalFlow() {
9
9
  // 1. Setup Client & Wallets
10
- const client = new ConfidentialTransferClient(
11
- RPC_URL,
12
- "0x29E4fd434758b1677c10854Fa81C2fc496D76E62",
13
- 2201,
14
- );
10
+ const client = new ConfidentialTransferClient(RPC_URL, 2201);
15
11
 
16
12
  const provider = new ethers.JsonRpcProvider(RPC_URL);
17
13
  const sender = new ethers.Wallet(process.env.SENDER_PRIVATE_KEY, provider);
@@ -25,7 +21,7 @@ async function minimalFlow() {
25
21
  await client.ensureAccount(recipient);
26
22
 
27
23
  const TOKEN = "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9";
28
- const amount = ethers.parseUnits("0.001", 6);
24
+ const amount = ethers.parseUnits("0.1", 2);
29
25
  let res;
30
26
  // 3. DEPOSIT: Move public ERC20 into the confidential contract
31
27
  res = await client.confidentialDeposit(sender, TOKEN, amount);
@@ -36,11 +32,11 @@ async function minimalFlow() {
36
32
  sender,
37
33
  recipient.address,
38
34
  TOKEN,
39
- amount / 2n,
35
+ ethers.parseUnits("0.05", 2),
40
36
  );
41
37
  console.log("Transfer TX Hash:", EXPLORER_URL + res.hash);
42
38
  // 5. WITHDRAW: Convert confidential balance back to public ERC20
43
- res = await client.withdraw(recipient, TOKEN, amount / 4n);
39
+ res = await client.withdraw(recipient, TOKEN, ethers.parseUnits("0.05", 2));
44
40
  console.log("Withdraw TX Hash:", EXPLORER_URL + res.hash);
45
41
  console.log("Confidential flow complete.");
46
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fairblock/stabletrust",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
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",
package/src/client.js CHANGED
@@ -2,7 +2,7 @@ import { ethers } from "ethers";
2
2
  import {
3
3
  CONTRACT_ABI,
4
4
  ERC20_ABI,
5
- DEFAULT_CONFIG,
5
+ getStableTrustContractAddress,
6
6
  TEMPO_FEE_TOKEN_ADDRESS,
7
7
  } from "./constants.js";
8
8
  import { deriveKeys, decryptCiphertext, combineCiphertext } from "./crypto.js";
@@ -27,23 +27,48 @@ export class ConfidentialTransferClient {
27
27
  * Create a new ConfidentialTransferClient instance
28
28
  *
29
29
  * @param {string} rpcUrl - RPC endpoint URL
30
- * @param {string} contractAddress - Confidential transfer contract address
31
- * @param {number} chainId - Chain ID
30
+ * @param {string|number} contractAddressOrChainId - Contract address or chain ID
31
+ * @param {number} [chainId] - Chain ID when contract address is provided
32
32
  */
33
- constructor(rpcUrl, contractAddress, chainId) {
33
+ constructor(rpcUrl, contractAddressOrChainId, chainId) {
34
34
  // Validate required config
35
35
  if (!rpcUrl) {
36
36
  throw new Error("rpcUrl is required");
37
37
  }
38
- if (!contractAddress) {
39
- throw new Error("contractAddress is required");
38
+
39
+ let resolvedChainId;
40
+ let resolvedContractAddress;
41
+
42
+ if (typeof contractAddressOrChainId === "number" && chainId === undefined) {
43
+ resolvedChainId = contractAddressOrChainId;
44
+ resolvedContractAddress = getStableTrustContractAddress(resolvedChainId);
45
+ } else {
46
+ resolvedChainId = chainId;
47
+ resolvedContractAddress =
48
+ contractAddressOrChainId ||
49
+ getStableTrustContractAddress(resolvedChainId);
50
+ }
51
+
52
+ if (!resolvedChainId) {
53
+ throw new Error("chainId is required");
54
+ }
55
+ if (!resolvedContractAddress) {
56
+ const supportedChainIds = [2201, 1244, 84532, 11155111, 421614, 42431]
57
+ .map(String)
58
+ .join(", ");
59
+ throw new Error(
60
+ `contractAddress is required for chainId ${resolvedChainId}. No default StableTrust contract is configured for this chain. Supported chainIds: ${supportedChainIds}`,
61
+ );
62
+ }
63
+ if (!ethers.isAddress(resolvedContractAddress)) {
64
+ throw new Error(`Invalid contractAddress: ${resolvedContractAddress}`);
40
65
  }
41
66
 
42
67
  // Build config
43
68
  this.config = {
44
69
  rpcUrl,
45
- contractAddress,
46
- chainId,
70
+ contractAddress: ethers.getAddress(resolvedContractAddress),
71
+ chainId: Number(resolvedChainId),
47
72
  };
48
73
 
49
74
  // WASM will be auto-initialized on first use
package/src/constants.js CHANGED
@@ -20,13 +20,18 @@ export const ERC20_ABI = [
20
20
  "function balanceOf(address account) external view returns (uint256)",
21
21
  ];
22
22
 
23
- export const DEFAULT_CONFIG = {
24
- CHAIN_ID: 421614,
25
- EXPLORER_URL: "https://sepolia.arbiscan.io/tx/",
26
- RPC_URL: "https://sepolia-rollup.arbitrum.io/rpc",
27
- CONTRACT_ADDRESS: "0x30bAc8a17DCACbA7f70F305f4ad908C9fd6d3E2E",
28
- TOKEN_ADDRESS: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
29
- };
30
-
31
23
  export const TEMPO_FEE_TOKEN_ADDRESS =
32
24
  "0x20c0000000000000000000000000000000000000";
25
+
26
+ export const STABLETRUST_CONTRACTS_BY_CHAIN_ID = Object.freeze({
27
+ 2201: "0x29E4fd434758b1677c10854Fa81C2fc496D76E62",
28
+ 1244: "0xf085e801a6FD9d03b09566a738734B7e2Bb065De",
29
+ 84532: "0x6FE45A71F5232a4E5e583Ae31A538360fB1e6aDb",
30
+ 11155111: "0x81a2c161c0327464430658516eE74A669feFC7bC",
31
+ 421614: "0xa59462200F6E438c538b914eB5F980B3Fa723aA0",
32
+ 42431: "0xB7bdce025c8a25e341Cb55795f8ba865AB3e392C",
33
+ });
34
+
35
+ export function getStableTrustContractAddress(chainId) {
36
+ return STABLETRUST_CONTRACTS_BY_CHAIN_ID[Number(chainId)] || null;
37
+ }
package/src/index.d.ts CHANGED
@@ -10,6 +10,14 @@ declare module "@fairblock/stabletrust" {
10
10
  chainId: number;
11
11
  }
12
12
 
13
+ export type StableTrustChainId =
14
+ | 1244
15
+ | 2201
16
+ | 42431
17
+ | 84532
18
+ | 421614
19
+ | 11155111;
20
+
13
21
  /**
14
22
  * Encryption keys
15
23
  */
@@ -71,6 +79,13 @@ declare module "@fairblock/stabletrust" {
71
79
  * WASM auto-initializes on first use - no manual initialization required!
72
80
  */
73
81
  export class ConfidentialTransferClient {
82
+ /**
83
+ * Create a new ConfidentialTransferClient
84
+ * @param rpcUrl RPC endpoint URL
85
+ * @param chainId Chain ID (uses default StableTrust contract for known networks)
86
+ */
87
+ constructor(rpcUrl: string, chainId: number);
88
+
74
89
  /**
75
90
  * Create a new ConfidentialTransferClient
76
91
  * @param rpcUrl RPC endpoint URL
@@ -218,10 +233,12 @@ declare module "@fairblock/stabletrust" {
218
233
  export const ERC20_ABI: any[];
219
234
 
220
235
  /**
221
- * Default configuration values
236
+ * StableTrust contract addresses by chain id
237
+ */
238
+ export const STABLETRUST_CONTRACTS_BY_CHAIN_ID: Record<number, string>;
239
+
240
+ /**
241
+ * Resolve StableTrust contract address by chain id
222
242
  */
223
- export const DEFAULT_CONFIG: {
224
- CHAIN_ID: number;
225
- EXPLORER_URL: string;
226
- };
243
+ export function getStableTrustContractAddress(chainId: number): string | null;
227
244
  }
package/src/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  export { ConfidentialTransferClient } from "./client.js";
2
2
  export { deriveKeys, decryptCiphertext, combineCiphertext } from "./crypto.js";
3
3
  export { encodeTransferProof, encodeWithdrawProof } from "./utils.js";
4
- export { CONTRACT_ABI, ERC20_ABI, DEFAULT_CONFIG } from "./constants.js";
4
+ export {
5
+ CONTRACT_ABI,
6
+ ERC20_ABI,
7
+ STABLETRUST_CONTRACTS_BY_CHAIN_ID,
8
+ getStableTrustContractAddress,
9
+ } from "./constants.js";
5
10
  // Note: initializeWasm is now internal - WASM auto-initializes on first client use