Skip to content

Repository files navigation

Confidential Transfers SDK

npm version crates.io CI License: Apache-2.0

Open-source TypeScript SDK for Token-2022 Confidential Transfers on Solana, built on @solana/kit (web3.js v2). It packages ElGamal/AES key handling, zero-knowledge proof generation, proof-context accounts, and the confidential-transfer instructions into a handful of clean async functions — so you can add encrypted balances and private transfers without hand-assembling the primitives.

A Rust crate mirroring the same helpers is published alongside it — see Rust.

Status: v1.0.1 — stable API. The public surface follows semantic versioning; breaking changes will bump the major version. Confidential transfers depend on Solana's ZK ElGamal Proof Program: this SDK is developed and validated against a local validator running that program plus a client-matching Token-2022 build (see Local development). Verify current support on your target cluster before deploying beyond a local validator. Runtime: Node ≥ 20.

Features

  • configureAccount — enable a Token-2022 account for confidential transfers (with the PubkeyValidity ZK proof)
  • deposit — move tokens from the public balance into the confidential pending balance
  • applyPendingBalance — roll the pending balance into the spendable available balance
  • decryptBalance — decrypt your own available balance locally (read-only)
  • transfer — privately transfer an encrypted amount (equality + ciphertext-validity + range proofs, verified via context-state accounts)
  • Auditor selective disclosure — derive an auditor ElGamal identity and recover transfer amounts on an auditor-enabled mint, without the power to spend

Keys are derived deterministically from the account owner's wallet signer and bound to (owner, mint), so they are recoverable from the wallet alone and never need to be stored. The derivation matches the reference Rust solana-zk-sdk vector.

Install

npm install @softseco/confidential-transfers

In a Solana app you'll already have the peers this builds on: @solana/kit and @solana-program/token-2022.

Usage

import {
  configureAccount,
  deposit,
  applyPendingBalance,
  decryptBalance,
  transfer,
} from "@softseco/confidential-transfers";

// 1. enable Alice's account for confidential transfers
const { token } = await configureAccount({ rpc, rpcSubscriptions, payer, owner: alice, mint });

// 2. move 1000 public tokens into Alice's confidential pending balance
await deposit({ rpc, rpcSubscriptions, payer, owner: alice, mint, amount: 1000n, decimals });

// 3. roll pending -> available
await applyPendingBalance({ rpc, rpcSubscriptions, payer, owner: alice, mint });

// 4. read your own balance (decrypted locally; nothing is revealed on-chain)
const balance = await decryptBalance({ rpc, owner: alice, mint }); // 1000n

// 5. privately transfer 1000 to Bob
await transfer({
  rpc,
  rpcSubscriptions,
  payer,
  owner: alice,
  mint,
  destinationOwner: bob.address,
  amount: 1000n,
});

A full, runnable round trip lives in examples/confidential-transfer.ts:

# with a local validator running (see Local development):
npm run example

Auditor selective disclosure

A mint can designate an auditor ElGamal public key. Once set, every confidential transfer on that mint additionally encrypts the amount to the auditor, who — and only who — can recover it, without being able to spend and without weakening anyone else's confidentiality.

import {
  deriveAuditorElgamalKeypair,
  getAuditorElgamalPubkey,
  decryptTransferAmountAsAuditor,
} from "@softseco/confidential-transfers";

// The auditor derives its ElGamal identity from its own wallet (nothing stored):
const auditorKeypair = await deriveAuditorElgamalKeypair(auditorWallet);

// Its public key goes into the mint's confidential-transfer config at mint creation:
const auditorElgamalPubkey = getAuditorElgamalPubkey(auditorKeypair);

// Senders route transfers to the auditor by passing that pubkey:
await transfer({ rpc, rpcSubscriptions, payer, owner: alice, mint, destinationOwner: bob.address, amount: 1000n, auditorElgamalPubkey });

// Given a confirmed transfer's signature, the auditor recovers the amount:
const amount = await decryptTransferAmountAsAuditor({ rpc, signature, auditorKeypair }); // 1000n

API

Function Purpose Notable inputs / output
configureAccount Configure a Token-2022 account for CT rpc, rpcSubscriptions, payer, owner, mint{ token, signature }
deposit Public balance → confidential pending , amount, decimals{ token, signature }
applyPendingBalance Pending → available rpc, rpcSubscriptions, payer, owner, mint{ token, signature }
decryptBalance Decrypt your available balance (read-only) rpc, owner, mintbigint
transfer Private transfer between accounts , owner, mint, destinationOwner (or destinationToken), amount, optional auditorElgamalPubkey{ sourceToken, destinationToken, signatures }
deriveAuditorElgamalKeypair Derive the auditor's ElGamal keypair from its wallet signerElGamalKeypair
getAuditorElgamalPubkey Auditor pubkey for a mint's CT config auditorKeypairAddress
decryptTransferAmountAsAuditor Recover a transfer's amount as the auditor rpc, signature, auditorKeypairbigint

Every function accepts an optional programAddress (defaults to Token-2022) and derives the owner's ElGamal/AES keys from the owner signer — no key storage required.

Rust

The same helpers — the five core operations plus the auditor utilities — are published as a Rust crate, softseco-confidential-transfers:

cargo add softseco-confidential-transfers

Built on solana-zk-sdk and spl-token-client. Like the TypeScript SDK, the crate's transfer verifies its ZK proofs via context-state accounts and is validated end-to-end against a local validator (rust/tests/ct_integration.rs). See rust/README.md for the crate API and details.

Local development

Confidential-transfer instructions require an on-chain Token-2022 program that matches the client, plus the ZK ElGamal Proof Program. The on-chain tests and the example therefore run against a local validator:

# 1. build a Token-2022 program matching the @solana-program/token-2022 client
cargo build-sbf --manifest-path <token-2022-source>/program/Cargo.toml

# 2. start the validator with that program loaded (leave running)
TOKEN_2022_SO=$(find <token-2022-source> -name 'spl_token_2022.so' -path '*deploy*' | head -1) \
  npm run validator

# 3. in another terminal, run the on-chain integration tests
CT_LOCAL_PROGRAM=1 npm test

Without CT_LOCAL_PROGRAM=1 the on-chain tests are skipped and only the validator-free unit tests run — this is what CI does. See CONTRIBUTING.md for the full workflow.

Project status

v1.0.1 — the public API is stable. Both the TypeScript package and the Rust crate ship the five core operations plus auditor selective disclosure, each with CI, and transfer is validated end-to-end (TypeScript and Rust) against a local validator. Changes are tracked in CHANGELOG.md.

Planned next:

  • Broaden cluster coverage as the ZK ElGamal Proof Program rolls out beyond local validators
  • Additional worked examples (end-to-end auditor flow, multi-party transfers)

Security

Confidential transfers are cryptographic and security-sensitive. To report a vulnerability, see SECURITY.md — please do not open a public issue for security reports.

License

Apache-2.0. See LICENSE.

About

Open-source TypeScript & Rust SDK for Token-2022 Confidential Transfers on Solana — encrypted balances, private transfers, and auditor selective disclosure.

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages