Skip to content

Token Support

The SDK supports ETH and EMT stablecoins (zkUSD, zkEUR, zkPLN).

Supported Tokens

TokenDecimalsFiat Backing
ETH18-
zkUSD6US Dollar
zkEUR6Euro
zkPLN6Polish Zloty

Token IDs

Tokens are identified by their contract address as a bigint:

typescript
const tokenId = BigInt(tokenAddress);

// ETH uses token ID 0
const ethTokenId = 0n;

Getting Token Addresses

typescript
import { DEPLOYMENTS } from '@zkprivacy/sdk';

const { tokens } = DEPLOYMENTS.remote;

console.log('zkUSD:', tokens.zkUSD);
console.log('zkEUR:', tokens.zkEUR);
console.log('zkPLN:', tokens.zkPLN);

Token Balances

Single Token

typescript
const tokenId = BigInt(DEPLOYMENTS.remote.tokens.zkUSD);
const balance = client.getBalanceByTokenId(tokenId);

All Tokens

typescript
const balances = client.getAllBalances();

for (const [tokenId, balance] of balances) {
  console.log(`Token ${tokenId}: ${balance}`);
}

ETH Balance

typescript
// Shorthand for ETH (token ID 0)
const ethBalance = client.getBalance();

// Or explicitly
const ethBalance = client.getBalanceByTokenId(0n);

Token Transfers

Always specify tokenId for non-ETH transfers:

typescript
import { parseUnits } from 'viem';

await client.transfer({
  recipient: 'zks1...',
  amount: parseUnits('100', 6),  // 100 USDC
  tokenId: BigInt(DEPLOYMENTS.remote.tokens.zkUSD),
});

Token Utilities

Format for Display

typescript
import { formatTokenAmount } from '@zkprivacy/sdk';

formatTokenAmount(1000000n, 'zkUSD');  // "1.00"
formatTokenAmount(1234567n, 'zkUSD');  // "1.23"

Parse User Input

typescript
import { parseTokenAmount } from '@zkprivacy/sdk';

parseTokenAmount('100.50', 'zkUSD');   // 100500000n
parseTokenAmount('1,234.56', 'zkUSD'); // 1234560000n

Token Lookup

typescript
import { getTokenBySymbol, getTokenByAddress } from '@zkprivacy/sdk';

const token = getTokenBySymbol('zkUSD');
// { symbol: 'zkUSD', decimals: 6, name: 'ZK US Dollar', ... }

const token = getTokenByAddress('0x...');

Shielding Tokens

Shield to Self

typescript
await client.shield({
  amount: parseUnits('100', 6),
  tokenId: BigInt(tokenAddress),
});

Shield to Others

typescript
import { shieldTo } from '@zkprivacy/sdk';

await shieldTo(config, {
  recipient: 'zks1...',
  amount: '100',
  tokenAddress: DEPLOYMENTS.remote.tokens.zkUSD,
  walletClient,
});

Unshielding Tokens

typescript
await client.unshield({
  recipient: '0x...',
  amount: parseUnits('100', 6),
  tokenId: BigInt(DEPLOYMENTS.remote.tokens.zkUSD),
});

EMT Token ABI

Use the EMT ABI for direct contract interaction:

typescript
import { EMT_ABI } from '@zkprivacy/sdk';

// Read balance
const balance = await publicClient.readContract({
  address: tokenAddress,
  abi: EMT_ABI,
  functionName: 'balanceOf',
  args: [account],
});

// Shield directly
await walletClient.writeContract({
  address: tokenAddress,
  abi: EMT_ABI,
  functionName: 'shield',
  args: [amount, commitment, encryptedNote],
});

Working with Decimals

EMT tokens use 6 decimals (like USDC):

typescript
import { parseUnits, formatUnits } from 'viem';

// Parse: "100.50" → 100500000n
const amount = parseUnits('100.50', 6);

// Format: 100500000n → "100.50"
const display = formatUnits(100500000n, 6);

ETH uses 18 decimals:

typescript
import { parseEther, formatEther } from 'viem';

const amount = parseEther('1.5');  // 1.5 ETH in wei
const display = formatEther(amount);

Multi-Token Notes

Each note is tied to a specific token. You cannot:

  • Transfer zkUSD with a zkEUR note
  • Consolidate notes of different tokens

The SDK handles this automatically - it selects notes matching the transfer token.

Released under the MIT License.