The TypeScript SDK for Shielded Protocol. Provides everything you need to add private, ZK-backed transactions to your Stellar dApp — from proof generation to React hooks to compliance tooling.
This is a monorepo containing three packages:
| Package | Version | Description |
|---|---|---|
@shielded/core |
0.1.0 | Proof generation, commitments, Merkle tree, crypto primitives |
@shielded/react |
0.1.0 | React hooks and context provider for UI integration |
@shielded/compliance |
0.1.0 | Viewing key management and shielded CLI for auditors |
Prerequisites: Node.js 18+, pnpm
git clone https://github.com/Shielded-Protocol/shielded-sdk
cd shielded-sdk
pnpm install
# Build all packages
pnpm build
# Run tests across all packages
pnpm test
# Type check
pnpm typecheckThe foundation package. Handles all cryptographic operations — no React required.
- Generates random shielded notes (secret + commitment + nullifier)
- Builds and queries the Poseidon Merkle tree
- Generates and verifies Groth16 proofs (via snarkjs + WASM circuits)
- Serializes/deserializes notes for encrypted storage
import { createNote, serializeNote, deriveCommitment } from '@shielded/core';
// Create a new note (random 31-byte secret generated internally)
const note = await createNote(
1_000_000n, // amount: 1 USDC (6 decimals)
1n // tokenId: identifies which token
);
// note.commitment → safe to publish on-chain
// note.nullifier → used when withdrawing (derived from secret)
// note.secret → NEVER share or store in plaintext
console.log(note.commitment);
// → "12345678901234567890123456789012345678901234567890123456789012"
// Serialize for local storage
const serialized = serializeNote(note);
localStorage.setItem('note', JSON.stringify(serialized));
// Verify a commitment is correctly formed
const commitment = await deriveCommitment(note.secret, note.amount, note.tokenId);
console.log(commitment === note.commitment); // → trueimport { generateWithdrawProof } from '@shielded/core';
const proof = await generateWithdrawProof({
note,
merkleTree, // fetched from the on-chain contract
recipient: 'GXXX...', // Stellar address to receive funds
relayer: null, // optional: address that pays the gas fee
fee: 0n, // optional: relayer fee in token units
});
// proof.proof → submit this to the on-chain verifier
// proof.publicSignals → public inputs (root, nullifier, recipient)React hooks and a context provider. Wraps @shielded/core with loading states, error handling, and Freighter wallet integration.
import { ShieldedProvider } from '@shielded/react';
import { Networks } from '@stellar/stellar-sdk';
function App() {
return (
<ShieldedProvider
networkPassphrase={Networks.TESTNET}
poolAddress="CXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
>
<YourApp />
</ShieldedProvider>
);
}import { useDeposit } from '@shielded/react';
function DepositForm() {
const { deposit, status, error } = useDeposit();
const handleDeposit = async () => {
// Generates a note, creates a commitment, and submits to the pool contract
await deposit(
1_000_000n, // amount: 1 USDC
1n, // tokenId
'GUSDC...' // Stellar asset contract address
);
};
return (
<div>
<button onClick={handleDeposit} disabled={status !== 'idle'}>
{status === 'idle' ? 'Shield 1 USDC' : status}
</button>
{error && <p>Error: {error.message}</p>}
</div>
);
}import { useWithdraw } from '@shielded/react';
function WithdrawButton({ note }) {
const { withdraw, status, proofStep } = useWithdraw();
return (
<div>
<button
onClick={() => withdraw(note, 'GRECIPIENT...')}
disabled={status !== 'idle'}
>
Withdraw
</button>
{status === 'proving' && (
<p>Generating proof… step {proofStep}/4</p>
)}
</div>
);
}import { useShieldedBalance } from '@shielded/react';
function BalanceDisplay() {
const { balance, notes, loading } = useShieldedBalance();
if (loading) return <p>Loading…</p>;
return (
<p>Shielded balance: {balance.toString()} (across {notes.length} notes)</p>
);
}| Hook | Returns | Description |
|---|---|---|
useDeposit() |
{ deposit, status, error } |
Deposit tokens into the shielded pool |
useWithdraw() |
{ withdraw, status, proofStep } |
Withdraw with ZK proof generation |
useShieldedBalance() |
{ balance, notes, loading } |
Read private balance from local notes |
useProofGeneration() |
{ generate, status, progress } |
Low-level proof generation hook |
Viewing key management for auditors and compliance-required users.
A viewing key is an encryption of your note secret, wrapped specifically for a named auditor's public key. It lets that auditor verify that you made a specific transaction — without seeing any of your other activity.
You create viewing keys. You control who gets them. You can revoke them.
import { issueViewingKey, encryptForAuditor } from '@shielded/compliance';
// Encrypt the viewing key for a specific auditor
const viewingKey = await issueViewingKey({
note,
auditorPublicKey: 'GAUDITOR...',
commitment: note.commitment,
});
// Register it on-chain (stores the encrypted key in the compliance-registry contract)
await registerViewingKey({
viewingKey,
poolAddress: 'CPOOL...',
network: Networks.TESTNET,
});Install globally:
npm install -g @shielded/complianceVerify a set of positions using a viewing key you received:
# Audit all positions accessible with this viewing key
shielded audit \
--viewing-key "vk:abc123..." \
--pool "CPOOL..." \
--network testnet \
--format table
# Verify a single commitment exists on-chain
shielded verify-commitment \
--commitment "12345..." \
--network testnetExample output:
┌─────────────────┬───────────┬──────────────┬────────┐
│ Commitment │ Amount │ Token │ Status │
├─────────────────┼───────────┼──────────────┼────────┤
│ 1234...abcd │ 1,000,000 │ USDC │ Unspent│
│ 5678...efgh │ 500,000 │ USDC │ Spent │
└─────────────────┴───────────┴──────────────┴────────┘
packages/
├── core/ ← @shielded/core — crypto, proof gen, Merkle tree
├── react/ ← @shielded/react — hooks and provider
└── compliance/ ← @shielded/compliance — viewing keys + CLI
See CONTRIBUTING.md.
Browse Wave-ready issues →
Good first issues are labeled layer:sdk and difficulty:easy.
| Repo | Description |
|---|---|
| shielded-circuits | Circom circuits that this SDK calls via snarkjs |
| shielded-contracts | Soroban contracts this SDK submits transactions to |
| shielded-app | Reference frontend built on top of this SDK |
MIT