Skip to main content

TRON Integration

FHE-powered private token vaults on TRON blockchain.

V0.1 Alpha

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:

  1. Generate FHE keys — You create keys locally. Your secret key (clientKey) never leaves your machine.
  2. Register keys — ServerKey and PublicKey are registered with the coprocessor.
  3. Deploy Vault — You deploy your vault contract to TRON (or use pre-deployed).
  4. Encrypt operation — You encrypt the operation details (transfer or withdraw). No one sees the plaintext.
  5. Submit operation — Your vault contract sends the encrypted request to the coprocessor via TronWeb.
  6. Compute on FHE — The coprocessor does math on encrypted data. It updates balances without knowing what they are.
  7. Callback result — New encrypted result CID is written back to your vault contract.
  8. Decrypt — Only you can decrypt and see the actual balances.
  9. Withdraw — For withdraw operations, tokens are transferred from the vault to your wallet.

Zero-Trust Security

Your keys never leave your machine:

ComponentWhere It LivesWho Can Access
ClientKeyYour machine onlyOnly you
ServerKeyZKSDK CoprocessorCan compute, cannot decrypt
PublicKeyZKSDK CoprocessorAnyone 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 0x prefix)

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:

  1. Generate FHE keys locally (~40 seconds)
  2. Initialize vault with your keys
  3. Encrypt a private transfer
  4. Submit on-chain via TronWeb
  5. Wait for oracle processing
  6. Show decrypted result
  7. 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

ResourceValue
NetworkShasta Testnet
CoProcessor ContractTQc68uCkmMGUAAwHhXQwz5GUcQJ5F3G2cp
ExampleTokenVaultTDoXyyTRqWC8AAhzkrF6SuB3nTRRKrtMVn
MockTokenTG2Kv3BBadz9anyvYTnDn4TxEHZHkPvAH5
FHE Worker URLhttps://alpha.coprocessor.zksdk.com
RPC URLhttps://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
});
TypeStatus
postgresAvailable
celestia, avail, eigenda, ipfsComing 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

PackagePlatformVersion
@zksdk/corenpm0.1.7
@zksdk/js-private-token-slots-fhenpm0.1.8
@zksdk/evm-corenpm0.1.1
tronwebnpm6.x

Limitations (Alpha)

Current Limitations
  • 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:

"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