TRON Integration
FHE-powered private token vaults on TRON blockchain.
This is an early release of TRON support. It is for testing purposes only — do not use with real value. APIs may change.
Overview
Private Token Slots for TRON lets you build confidential token vaults on TRON where:
- Balances are encrypted (no one sees how much anyone holds)
- Transfers happen privately (sender, receiver, amount all hidden)
- Only the vault owner can decrypt balances
Key Insight: The same @zksdk/js-private-token-slots-fhe SDK works for TRON and EVM. Only the chain interaction library differs (TronWeb vs ethers.js).
┌─────────────────────────────────────────────────────────┐
│ Your Token Vault │
├─────────┬─────────┬─────────┬─────────┬────────────────┤
│ Slot 0 │ Slot 1 │ Slot 2 │ Slot 3 │ ... Slot 255 │
│ [ENC] │ [ENC] │ [ENC] │ [ENC] │ [ENC] │
└─────────┴─────────┴─────────┴─────────┴────────────────┘
↓ Transfer 50 from Slot 0 → Slot 1
┌─────────┬─────────┬─────────┬─────────┬────────────────┐
│ [ENC] │ [ENC] │ [ENC] │ [ENC] │ [ENC] │
└─────────┴─────────┴─────────┴─────────┴────────────────┘
All balances remain encrypted throughout!
How It Works
Architecture
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Your dApp │ │ TRON │ │ ZKSDK │
│ │ │ (Shasta) │ │ Coprocessor │
│ │ │ │ │ │
│ 1. Generate │ │ │ │ │
│ FHE keys │────────────────────────→│ 2. Register │
│ │ │ │ │ keys │
│ 3. Deploy │ │ │ │ │
│ Vault │────→│ TokenVault │ │ │
│ │ │ │ │ │
│ 4. Encrypt │ │ │ │ │
│ operation │ │ │ │ │
│ (transfer │ │ 5. Submit │ │ │
│ or withdraw) │────→│ operation │────→│ 6. Compute │
│ │ │ │ │ on FHE │
│ │ │ │ │ │
│ 8. Decrypt │←────│ 7. Callback │←────│ │
│ (only you)│ │ result │ │ │
│ │ │ │ │ │
│ 9. Withdraw: │ │ Tokens sent │ │ │
│ receive │←────│ to wallet │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
What happens at each step:
- Generate FHE keys — You create keys locally. Your secret key (
clientKey) never leaves your machine. - Register keys — ServerKey and PublicKey are registered with the coprocessor.
- Deploy Vault — You deploy your vault contract to TRON (or use pre-deployed).
- Encrypt operation — You encrypt the operation details (transfer or withdraw). No one sees the plaintext.
- Submit operation — Your vault contract sends the encrypted request to the coprocessor via TronWeb.
- Compute on FHE — The coprocessor does math on encrypted data. It updates balances without knowing what they are.
- Callback result — New encrypted result CID is written back to your vault contract.
- Decrypt — Only you can decrypt and see the actual balances.
- Withdraw — For withdraw operations, tokens are transferred from the vault to your wallet.
Zero-Trust Security
Your keys never leave your machine:
| Component | Where It Lives | Who Can Access |
|---|---|---|
| ClientKey | Your machine only | Only you |
| ServerKey | ZKSDK Coprocessor | Can compute, cannot decrypt |
| PublicKey | ZKSDK Coprocessor | Anyone can encrypt to vault |
The coprocessor mathematically cannot decrypt your data. It only has evaluation keys that can perform operations on ciphertext.
Quick Start
Prerequisites
- Node.js 18+
- Testnet TRX (get from Shasta faucet)
- TRON private key (hex format, no
0xprefix)
Install Dependencies
# Clone the example repo
git clone https://github.com/zksdk-labs/example-tron-fhe-slot-vault
cd example-tron-fhe-slot-vault
# Install
npm install
# Configure environment
cp .env.example .env
# Add your TRON_PRIVATE_KEY to .env
Run the Full Demo
npm run demo
This will:
- Generate FHE keys locally (~40 seconds)
- Initialize vault with your keys
- Encrypt a private transfer
- Submit on-chain via TronWeb
- Wait for oracle processing
- Show decrypted result
- Withdraw tokens back to your wallet!
Step-by-Step Guide
1. Generate FHE Keys
Generate FHE keys locally and register them with the coprocessor:
import { SlotVaultClient } from "@zksdk/js-private-token-slots-fhe";
const client = new SlotVaultClient({
workerUrl: "https://alpha.coprocessor.zksdk.com",
});
// Generate keys locally (takes ~40 seconds)
const { vaultKeyId, clientKey, serverKey, publicKey } =
await client.createVault();
// IMPORTANT: Save your clientKey securely - it's YOUR SECRET
// The coprocessor CANNOT decrypt without it
console.log("Vault Key ID:", vaultKeyId);
console.log("ClientKey size:", (clientKey.length / 1024).toFixed(1), "KB");
# Or run via npm script
npm run 1:keys
2. Deploy or Use Pre-Deployed Vault
You can use the pre-deployed vault on Shasta, or deploy your own:
import { TronWeb } from "tronweb";
const tronWeb = new TronWeb({
fullHost: "https://api.shasta.trongrid.io",
privateKey: process.env.TRON_PRIVATE_KEY,
});
// Use pre-deployed vault
const VAULT_ADDRESS = "TDoXyyTRqWC8AAhzkrF6SuB3nTRRKrtMVn";
const vault = tronWeb.contract(VAULT_ABI, VAULT_ADDRESS);
# Or deploy your own
npm run 2:deploy
3. Initialize Vault
Link your FHE keys to the vault:
// Initialize with your vault key ID
const tx = await vault.initialize(vaultKeyId).send({
feeLimit: 100_000_000,
});
console.log("Vault initialized! TX:", tx);
npm run 3:init
4. Encrypt and Submit Private Transfer
Encrypt transfer parameters and submit on-chain:
// Encrypt transfer (sender slot, receiver slot, amount)
const senderSlot = 0;
const receiverSlot = 1;
const amount = 50;
const { encrypted_data } = client.encryptTransfer(
senderSlot,
receiverSlot,
amount
);
// Store encrypted data and get CID
const storageCid = await client.storeBalanceBlob(encrypted_data);
// Submit to vault contract via TronWeb
const circuitId = "private_token_slots_v1";
const tx = await vault.submitPrivateTransfer(circuitId, storageCid).send({
feeLimit: 200_000_000,
});
console.log("Transfer submitted! TX:", tx);
npm run 4:transfer
5. Check Result
Poll for the oracle to process the request:
const resultCid = await vault.balanceBlobCid().call();
console.log("Result CID:", resultCid);
npm run 5:result
6. Decrypt Result
Only you can decrypt the result using your clientKey:
// Fetch encrypted result
const encryptedResult = await client.fetchBalanceBlob(resultCid);
// Decrypt with your clientKey
const { balances, isValid } = client.decryptResult(encryptedResult);
console.log("Transfer valid:", isValid);
console.log("Slot 0 balance:", balances[0]);
console.log("Slot 1 balance:", balances[1]);
npm run 6:decrypt
7. Withdraw Tokens
Withdraw tokens from your private vault slot back to your wallet:
// Encrypt withdraw (slot index, amount)
const slotIndex = 0;
const withdrawAmount = 25;
const { encrypted_data } = client.encryptWithdraw(slotIndex, withdrawAmount);
// Store encrypted data and get CID
const withdrawCid = await client.storeBalanceBlob(encrypted_data);
// Submit withdraw to vault contract
const amountInUnits = BigInt(withdrawAmount) * BigInt(1_000_000); // TRC20 decimals
const tx = await vault.withdraw(amountInUnits.toString(), withdrawCid).send({
feeLimit: 200_000_000,
});
console.log("Withdraw submitted! TX:", tx);
npm run 7:withdraw
Network Configuration
| Resource | Value |
|---|---|
| Network | Shasta Testnet |
| CoProcessor Contract | TQc68uCkmMGUAAwHhXQwz5GUcQJ5F3G2cp |
| ExampleTokenVault | TDoXyyTRqWC8AAhzkrF6SuB3nTRRKrtMVn |
| MockToken | TG2Kv3BBadz9anyvYTnDn4TxEHZHkPvAH5 |
| FHE Worker URL | https://alpha.coprocessor.zksdk.com |
| RPC URL | https://api.shasta.trongrid.io |
View on Tronscan
Storage
Encrypted data is stored off-chain. Configure storage in your SDK setup:
const client = new SlotVaultClient({
workerUrl: "https://alpha.coprocessor.zksdk.com",
storageType: "postgres", // Current default
});
| Type | Status |
|---|---|
postgres | Available |
celestia, avail, eigenda, ipfs | Coming Soon |
See full Storage documentation for all options and configuration details.
Files Created
After running the demo:
keys/
├── client.key # YOUR SECRET - backup this!
├── vault-key-id.txt # Vault identifier (64-char hex)
└── last-request-cid.txt # Last submitted request
Packages
| Package | Platform | Version |
|---|---|---|
| @zksdk/core | npm | 0.1.7 |
| @zksdk/js-private-token-slots-fhe | npm | 0.1.8 |
| @zksdk/evm-core | npm | 0.1.1 |
| tronweb | npm | 6.x |
Limitations (Alpha)
- Slot balances: 0-255 per slot (8-bit)
- Slots per vault: Up to 256
- Not audited: Do not use with real value
Troubleshooting
"insufficient TRX"
Get testnet TRX from faucets:
- Shasta: https://shasta.tronex.io/
- Nile: https://nileex.io/join/getJoinPage
"TRON_PRIVATE_KEY required"
Copy .env.example to .env:
cp .env.example .env
Add your private key (hex format, no 0x prefix):
TRON_PRIVATE_KEY=your_hex_private_key_here
TronWeb connection issues
Ensure you're using the correct RPC URL:
const tronWeb = new TronWeb({
fullHost: "https://api.shasta.trongrid.io", // Shasta testnet
privateKey: process.env.TRON_PRIVATE_KEY,
});
Support
- GitHub: example-tron-fhe-slot-vault
- Issues: Report bugs
- Contact: Get in touch