@minkprivacy/core
v0.1.1
Published
Mink Privacy SDK - Core library for private Solana transactions
Downloads
32
Maintainers
Readme
@minkprivacy/core
Core SDK for private transactions on Solana using zero-knowledge proofs.
Install
npm install @minkprivacy/core
# or
pnpm add @minkprivacy/corePeer dependencies:
npm install @solana/web3.js @lightprotocol/hasher.rsQuick Start
import { MinkSDK } from '@minkprivacy/core';
const sdk = await MinkSDK.create({
connection, // @solana/web3.js Connection
wallet, // Wallet adapter (signMessage + signTransaction)
network: 'devnet', // 'devnet' | 'mainnet'
});
await sdk.authenticate();
// Deposit SOL into the privacy pool
const deposit = await sdk.cloak({ amount: 0.1 });
// Withdraw from the privacy pool
const withdraw = await sdk.reveal({ amount: 0.05, recipientAddress: '...' });
// Check stealth balance
const balance = await sdk.getStealthBalance();Architecture
@minkprivacy/core
├── MinkSDK ← High-level facade
├── crypto/ ← Keypairs, encryption (V1/V2/V3), ECDH
├── operations/ ← deposit, withdraw, balance, helpers
├── proofs/ ← ZK proof generation (snarkjs/Groth16)
├── merkle/ ← Poseidon-based Merkle tree
├── models/ ← Utxo, token definitions
├── storage/ ← IStorage, BrowserStorage, MemoryStorage
├── errors/ ← Typed error hierarchy
├── network/ ← Devnet/Mainnet config
├── inbox/ ← Private Inbox (stealth addresses)
├── viewing-keys/ ← Scoped viewing keys for auditing
├── logger/ ← ConsoleLogger, NoopLogger
├── auth/ ← Relayer authentication
├── events/ ← SDK event system
└── timestamp/ ← UTXO timestamp trackingAPI Reference
MinkSDK
Main entry point. Created via MinkSDK.create(config) or createMinkSDK(config).
interface PrivacySDKConfig {
connection: Connection;
wallet: WalletAdapter;
network?: 'devnet' | 'mainnet'; // default: 'devnet'
storage?: IStorage; // default: BrowserStorage
}Core Methods
| Method | Returns | Description |
|--------|---------|-------------|
| authenticate() | Promise<void> | Derive encryption keys from wallet signature |
| cloak(params) | Promise<CloakResult> | Deposit SOL into the privacy pool |
| cloakToken(params) | Promise<CloakResult> | Deposit SPL token (USDC/USDT) |
| reveal(params) | Promise<RevealResult> | Withdraw from the pool to any address |
| getStealthBalance() | Promise<StealthBalance> | Fetch and decrypt SOL balance |
| getTokenBalance(token) | Promise<TokenBalanceResult> | Fetch token balance |
| getAllBalances() | Promise<AllBalancesResult> | Fetch SOL + all token balances |
| estimateWithdrawFee(amount) | Promise<FeeEstimate> | Estimate withdrawal fee |
| dispose() | void | Clean up resources |
Inbox Methods
| Method | Returns | Description |
|--------|---------|-------------|
| inbox.create(params?) | Promise<CreateInboxResult> | Create a private inbox |
| inbox.forward(inbox) | Promise<{signature, amountForwarded}> | Forward to pool |
| inbox.getInboxes(mint?) | Promise<PrivateInbox[]> | List inboxes |
| inbox.getPendingInboxes() | Promise<PrivateInbox[]> | Inboxes with balance |
Auth Methods
| Method | Returns | Description |
|--------|---------|-------------|
| auth.authenticate(signMessage, walletAddress) | Promise<boolean> | Authenticate with relayer |
| auth.isAuthenticated() | boolean | Check auth status |
| auth.logout() | void | Clear auth token |
Events
sdk.on('deposit:confirmed', ({ signature, amount }) => { ... });
sdk.on('withdraw:confirmed', ({ signature, amount, fee }) => { ... });
sdk.on('balance:updated', ({ lamports }) => { ... });
sdk.on('error', ({ error }) => { ... });See docs/events.md for the full event list.
Cloak / Reveal Params
// Deposit SOL
await sdk.cloak({ amount: 0.5 }); // in SOL
// Deposit SPL token
await sdk.cloakToken({ token: 'USDC', amount: 1_000_000 }); // base units
// Withdraw SOL
await sdk.reveal({ amount: 0.3 }); // to self
await sdk.reveal({ amount: 0.3, recipientAddress: '...' }); // to any addressSubpath Exports
The package exposes granular subpath imports for tree-shaking:
import { EncryptionService, Keypair } from '@minkprivacy/core/crypto';
import { prove } from '@minkprivacy/core/proofs';
import { MerkleTree } from '@minkprivacy/core/merkle';
import { Utxo } from '@minkprivacy/core/models';
import { deposit, withdraw, getUtxos } from '@minkprivacy/core/operations';
import { BrowserStorage } from '@minkprivacy/core/storage';
import { MinkError, NetworkError } from '@minkprivacy/core/errors';
import { getNetworkConfig } from '@minkprivacy/core/network';
import { PrivateInboxManager } from '@minkprivacy/core/inbox';
import { ViewingKeyManager } from '@minkprivacy/core/viewing-keys';Full details for each module below.
Module Reference
crypto/ — Encryption & Key Management
See docs/crypto.md
Key exports:
| Export | Type | Description |
|--------|------|-------------|
| Keypair | class | ZK keypair (Poseidon-based) for UTXO ownership |
| EncryptionService | class | Multi-version encryption (V1/V2/V3) |
| serializeProofAndExtData | function | Serialize ZK proof for Solana instruction |
| ecdhSharedSecret | function | X25519 ECDH shared secret |
| deriveEncPrivKey | function | Derive X25519 key from ZK spending key |
| generateEphemeralKeypair | function | Fresh ephemeral keypair per operation |
| encryptNoteV3 / decryptNoteV3 | functions | V3 ECDH-based encryption |
| FIELD_SIZE | constant | BN254 scalar field |
| TOKENS | constant | SOL, USDC, USDT token definitions |
Encryption versions:
| Version | Algorithm | Key Size | Use Case | |---------|-----------|----------|----------| | V1 | AES-128-CTR + HMAC | 31 bytes | Legacy (deprecated) | | V2 | AES-256-GCM | 32 bytes | UTXO storage | | V3 | ECDH + AES-256-GCM | ephemeral | Stealth forwards (inbox) |
operations/ — Deposit, Withdraw, Balance
deposit(params) — Deposit SOL into privacy pool.
- Fetches existing UTXOs, generates ZK proof, creates on-chain transaction
- Supports fresh deposits and consolidation (merging existing UTXOs)
depositToken(params) — Deposit SPL token (USDC/USDT).
withdraw(params) — Withdraw SOL from privacy pool.
- Selects best UTXOs, validates Merkle root, generates ZK proof
- Submitted to relayer which executes the on-chain transaction
- Fee:
(amount × rate_bps / 10000) + rent_fee
getUtxos(params) — Fetch and decrypt all UTXOs for a wallet.
- Supports V1/V2/V3 encrypted outputs
- Checks spent status via nullifier PDAs
- Caches results in storage
getBalanceFromUtxos(utxos) — Sum UTXO amounts.
proofs/ — ZK Proof Generation
See docs/proofs.md
import { prove, parseProofToBytesArray } from '@minkprivacy/core/proofs';
const { proof, publicSignals } = await prove(
circuitInput,
'https://cdn.example.com/stealth.wasm',
'https://cdn.example.com/stealth.zkey',
);
const bytes = parseProofToBytesArray(proof);
// bytes.proofA (64 bytes), bytes.proofB (128 bytes), bytes.proofC (64 bytes)- Uses snarkjs for Groth16 proof generation
- Proof A is auto-negated for Solana BN254 verifier
- Browser-compatible (loads circuit files from URLs)
merkle/ — Merkle Tree
import { MerkleTree } from '@minkprivacy/core/merkle';
const tree = new MerkleTree(26, lightWasm);
tree.insert(commitment);
const { pathElements, pathIndices } = tree.path(0);- 26-level Poseidon Merkle tree (capacity: 2²⁶ = 67M leaves)
- Supports
insert,bulkInsert,update,path,serialize/deserialize
models/ — Utxo & Tokens
import { Utxo, createEmptyUtxo } from '@minkprivacy/core/models';
const utxo = new Utxo({ lightWasm, amount: 1_000_000, keypair, blinding, index: 42 });
const commitment = await utxo.getCommitment();
const nullifier = await utxo.getNullifier();Supported tokens: SOL, USDC, USDT (devnet + mainnet mints).
storage/ — Pluggable Storage
import { BrowserStorage, MemoryStorage } from '@minkprivacy/core/storage';
import type { IStorage } from '@minkprivacy/core/storage';| Class | Persistence | Use Case |
|-------|-------------|----------|
| BrowserStorage | localStorage | Default (browser) |
| SessionStorage | sessionStorage | Sensitive contexts |
| MemoryStorage | in-memory only | Tests, SSR |
Implements IStorage: getItem(key), setItem(key, value), removeItem(key).
errors/ — Error Hierarchy
import { MinkError, InsufficientBalanceError, ErrorCodes } from '@minkprivacy/core/errors';
try {
await sdk.reveal({ amount: 999 });
} catch (e) {
if (e instanceof InsufficientBalanceError) {
console.log(`Need ${e.required}, have ${e.available}`);
}
}| Error Class | Code | Retryable |
|-------------|------|-----------|
| WalletError | WALLET_ERROR | no |
| InitializationError | INITIALIZATION_ERROR | no |
| EncryptionError | ENCRYPTION_ERROR | no |
| ProofError | PROOF_ERROR | configurable |
| NetworkError | NETWORK_ERROR | yes |
| TransactionError | TRANSACTION_ERROR | configurable |
| InsufficientBalanceError | INSUFFICIENT_BALANCE | no |
| TimeoutError | TIMEOUT_ERROR | yes |
| ValidationError | VALIDATION_ERROR | no |
See ErrorCodes for all granular codes (e.g., WALLET_NOT_CONNECTED, UNKNOWN_ROOT).
network/ — Network Configuration
import { getNetworkConfig, DEVNET_CONFIG, MAINNET_CONFIG } from '@minkprivacy/core/network';
import type { NetworkType, NetworkConfig } from '@minkprivacy/core/network';
const config = getNetworkConfig('devnet');
// { rpcUrl, programId, relayerUrl, zkAssetsPath, explorerUrl, ... }Program ID is the same on both networks: MinkoCW871q3LjoJ1yHuGikT1BwgyeP1VimZha5ecm6.
inbox/ — Private Inbox (Stealth Addresses)
See docs/inbox.md
Private inboxes are stealth addresses that receive tokens from any source and auto-forward them into the privacy pool.
import { PrivateInboxManager } from '@minkprivacy/core/inbox';
const manager = new PrivateInboxManager({ lightWasm, connection, spendingKeypair, relayerUrl });
const { inbox } = await manager.createInbox();
const address = manager.getReceiveAddress(inbox); // share this
await manager.forwardToPool(inbox); // forward to pool- Registration uses ZK proof (proves ownership without revealing private key)
- Forward uses ECDH-derived blinding for output encryption
- Supports multiple inboxes per (wallet, mint) pair
viewing-keys/ — Scoped Viewing Keys
Viewing keys allow third parties to audit transactions without spending authority.
import { ViewingKeyManager, ViewingScope } from '@minkprivacy/core/viewing-keys';
const vkm = new ViewingKeyManager(lightWasm, spendingKeypair);
const vk = vkm.deriveViewingKey(ViewingScope.Full);
const serialized = vkm.serializeViewingKey(vk);
// serialized.url → "mink://view/..."
// serialized.qr → base58 string for QR codes| Scope | Access |
|-------|--------|
| Proxy | Inbox deposits/forwards only |
| Pool | Privacy pool transactions only |
| Full | Both inbox and pool |
logger/ — Logging
import { ConsoleLogger, NoopLogger } from '@minkprivacy/core';
const logger = new ConsoleLogger({ prefix: '[MyApp]', minLevel: 'warn' });SDK uses ConsoleLogger internally. Use NoopLogger to suppress output.
Network Details
| | Devnet | Mainnet |
|---|--------|---------|
| Program ID | MinkoCW871q3LjoJ1yHuGikT1BwgyeP1VimZha5ecm6 | Same |
| Relayer | https://devnet-api.minkprivacy.com | https://api.minkprivacy.com |
| ZK Assets | https://cdn.minkprivacy.com/zk-assets | Same |
