Skip to content

Commit 31101af

Browse files
niconiconiclaude
andcommitted
docs: add llms.txt for AI coding tool context
- llms.txt at repo root: full SDK context (config, API, types, examples) - docs/public/llms.txt: served at docs.o.cash/llms.txt for web access Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0014f0a commit 31101af

File tree

2 files changed

+321
-0
lines changed

2 files changed

+321
-0
lines changed

docs/public/llms.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# @ocash/sdk
2+
3+
> TypeScript ZKP SDK for privacy-preserving token operations via UTXO model and zk-SNARK proofs.
4+
5+
## Install
6+
7+
```bash
8+
pnpm add @ocash/sdk
9+
```
10+
11+
Three entry points:
12+
- `@ocash/sdk` — universal (MemoryStore)
13+
- `@ocash/sdk/browser` — browser (+ IndexedDbStore)
14+
- `@ocash/sdk/node` — Node.js (+ FileStore)
15+
16+
## Quick Start
17+
18+
```ts
19+
import { createSdk } from '@ocash/sdk';
20+
21+
const sdk = createSdk({
22+
chains: [{
23+
chainId: 11155111,
24+
entryUrl: 'https://entry.example.com',
25+
ocashContractAddress: '0x...',
26+
relayerUrl: 'https://relayer.example.com',
27+
merkleProofUrl: 'https://merkle.example.com',
28+
tokens: [],
29+
}],
30+
onEvent: (event) => console.log(event.type, event.payload),
31+
});
32+
33+
await sdk.core.ready();
34+
await sdk.wallet.open({ seed: 'your-secret-seed' });
35+
await sdk.sync.syncOnce();
36+
const balance = await sdk.wallet.getBalance({ chainId: 11155111 });
37+
await sdk.wallet.close();
38+
```
39+
40+
## Lifecycle
41+
42+
createSdk(config) → sdk.core.ready() → sdk.wallet.open({ seed }) → sdk.sync.start() → sdk.ops.* → sdk.wallet.close()
43+
44+
## Full API Reference: docs.o.cash

llms.txt

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
# @ocash/sdk
2+
3+
> TypeScript ZKP SDK for privacy-preserving token operations via UTXO model and zk-SNARK proofs.
4+
5+
## Install
6+
7+
```bash
8+
pnpm add @ocash/sdk
9+
```
10+
11+
Three entry points:
12+
- `@ocash/sdk` — universal (MemoryStore)
13+
- `@ocash/sdk/browser` — browser (+ IndexedDbStore)
14+
- `@ocash/sdk/node` — Node.js (+ FileStore)
15+
16+
## Quick Start
17+
18+
```ts
19+
import { createSdk } from '@ocash/sdk';
20+
21+
const sdk = createSdk({
22+
chains: [{
23+
chainId: 11155111,
24+
entryUrl: 'https://entry.example.com',
25+
ocashContractAddress: '0x...',
26+
relayerUrl: 'https://relayer.example.com',
27+
merkleProofUrl: 'https://merkle.example.com',
28+
tokens: [],
29+
}],
30+
onEvent: (event) => console.log(event.type, event.payload),
31+
});
32+
33+
await sdk.core.ready(); // Load WASM & circuits
34+
await sdk.wallet.open({ seed: 'your-secret-seed' }); // Derive keys, init storage
35+
await sdk.sync.syncOnce(); // Sync memos, nullifiers, merkle
36+
const balance = await sdk.wallet.getBalance({ chainId: 11155111 });
37+
await sdk.wallet.close(); // Release keys, flush storage
38+
```
39+
40+
## SDK Modules
41+
42+
sdk.core — WASM & circuit initialization (ready, reset)
43+
sdk.keys — BabyJubjub key derivation (deriveKeyPair, userPkToAddress, addressToUserPk)
44+
sdk.crypto — Commitments, nullifiers, memo encryption (commitment, nullifier, createRecordOpening)
45+
sdk.assets — Chain/token/relayer configuration (getChains, getTokens, syncRelayerConfig)
46+
sdk.storage — Persistence adapter (upsertUtxos, listUtxos, markSpent, getSyncCursor)
47+
sdk.wallet — Session, UTXOs, balance (open, close, getUtxos, getBalance, markSpent)
48+
sdk.sync — Memo/nullifier/Merkle sync (start, stop, syncOnce, getStatus)
49+
sdk.merkle — Merkle proofs & membership witnesses (getProofByCids, buildInputSecretsFromUtxos)
50+
sdk.planner — Coin selection, fee estimation (estimate, estimateMax, plan)
51+
sdk.zkp — zk-SNARK proof generation (proveTransfer, proveWithdraw)
52+
sdk.tx — Relayer request builder (buildTransferCalldata, buildWithdrawCalldata)
53+
sdk.ops — End-to-end orchestration (prepareTransfer, prepareWithdraw, prepareDeposit, submitRelayerRequest)
54+
55+
## Configuration
56+
57+
```ts
58+
interface OCashSdkConfig {
59+
chains: ChainConfigInput[]; // Required: chain configurations
60+
assetsOverride?: AssetsOverride; // WASM/circuit file URLs (string or string[] for chunks)
61+
storage?: StorageAdapter; // Default: MemoryStore
62+
runtime?: 'auto' | 'browser' | 'node' | 'hybrid';
63+
cacheDir?: string; // Node/hybrid: local asset cache directory
64+
merkle?: { mode?: 'remote' | 'local' | 'hybrid'; treeDepth?: number };
65+
sync?: { pageSize?: number; pollMs?: number; requestTimeoutMs?: number; retry?: { attempts?: number; baseDelayMs?: number; maxDelayMs?: number } };
66+
onEvent?: (event: SdkEvent) => void; // Event callback
67+
}
68+
69+
interface ChainConfigInput {
70+
chainId: number;
71+
rpcUrl?: string; // JSON-RPC URL
72+
entryUrl?: string; // Entry Service (memo/nullifier sync)
73+
ocashContractAddress?: Address; // OCash contract
74+
relayerUrl?: string; // Relayer service
75+
merkleProofUrl?: string; // Merkle proof service
76+
tokens?: TokenMetadata[];
77+
}
78+
79+
interface TokenMetadata {
80+
id: string; symbol: string; decimals: number; wrappedErc20: Address;
81+
viewerPk: [string, string]; freezerPk: [string, string];
82+
depositFeeBps?: number; withdrawFeeBps?: number;
83+
transferMaxAmount?: bigint | string; withdrawMaxAmount?: bigint | string;
84+
}
85+
```
86+
87+
## Transfer
88+
89+
```ts
90+
const keyPair = sdk.keys.deriveKeyPair(seed, nonce);
91+
92+
// Estimate fees first
93+
const estimate = await sdk.planner.estimate({
94+
chainId: 11155111, assetId: 'token-id', action: 'transfer', amount: 500000n,
95+
});
96+
// estimate.feeSummary.mergeCount / relayerFeeTotal / protocolFeeTotal
97+
98+
// Max transferable
99+
const max = await sdk.planner.estimateMax({
100+
chainId: 11155111, assetId: 'token-id', action: 'transfer',
101+
});
102+
// max.maxSummary.outputAmount
103+
104+
// Prepare (plan → merkle proof → witness → zk-SNARK proof → relayer request)
105+
const prepared = await sdk.ops.prepareTransfer({
106+
chainId: 11155111, assetId: 'token-id', amount: 500000n,
107+
to: recipientViewingAddress, // Hex: BabyJubjub compressed address
108+
ownerKeyPair: keyPair,
109+
publicClient, // viem PublicClient
110+
});
111+
112+
// Submit to relayer
113+
const result = await sdk.ops.submitRelayerRequest({ prepared, publicClient });
114+
const txHash = await result.waitRelayerTxHash;
115+
const receipt = await result.transactionReceipt;
116+
```
117+
118+
If more than 3 UTXOs needed, prepareTransfer returns `{ kind: 'merge' }` with merge steps. The planner handles this automatically with `autoMerge: true` (default).
119+
120+
## Withdraw
121+
122+
```ts
123+
const prepared = await sdk.ops.prepareWithdraw({
124+
chainId: 11155111, assetId: 'token-id', amount: 500000n,
125+
recipient: '0x1234...abcd', // EVM address to receive tokens
126+
ownerKeyPair: keyPair, publicClient,
127+
gasDropValue: 10000000000000000n, // Optional: 0.01 ETH gas drop
128+
});
129+
const result = await sdk.ops.submitRelayerRequest({ prepared, publicClient });
130+
```
131+
132+
## Deposit
133+
134+
```ts
135+
const ownerPub = sdk.keys.getPublicKeyBySeed(seed, nonce);
136+
const prepared = await sdk.ops.prepareDeposit({
137+
chainId: 11155111, assetId: 'token-id', amount: 1000000n,
138+
ownerPublicKey: ownerPub,
139+
account: walletAddress, // Depositor's EOA
140+
publicClient,
141+
});
142+
143+
// ERC-20 approval if needed
144+
if (prepared.approveNeeded && prepared.approveRequest) {
145+
await walletClient.writeContract(prepared.approveRequest);
146+
}
147+
await walletClient.writeContract(prepared.depositRequest);
148+
149+
// Or use submitDeposit for auto-approve:
150+
const result = await sdk.ops.submitDeposit({
151+
prepared, walletClient, publicClient, autoApprove: true,
152+
});
153+
```
154+
155+
## Key Management
156+
157+
```ts
158+
// Derive key pair (seed must be >= 16 characters)
159+
const keyPair = sdk.keys.deriveKeyPair('my-secret-seed', 'optional-nonce');
160+
// keyPair.user_sk.address_sk: bigint (secret key)
161+
// keyPair.user_pk.user_address: [bigint, bigint] (BabyJubjub public key)
162+
163+
// Public key only (no secret key exposure)
164+
const pubKey = sdk.keys.getPublicKeyBySeed(seed, nonce);
165+
166+
// Compress to viewing address
167+
const address = sdk.keys.userPkToAddress(pubKey); // 0x... (32 bytes)
168+
169+
// Decompress back
170+
const pk = sdk.keys.addressToUserPk(address);
171+
```
172+
173+
## Sync
174+
175+
```ts
176+
// One-shot sync
177+
await sdk.sync.syncOnce({
178+
chainIds: [11155111],
179+
resources: ['memo', 'nullifier', 'merkle'],
180+
signal: abortController.signal,
181+
});
182+
183+
// Background polling
184+
await sdk.sync.start({ pollMs: 10_000 });
185+
sdk.sync.stop(); // Stops polling + aborts in-flight sync
186+
187+
// Check status
188+
const status = sdk.sync.getStatus();
189+
// { 11155111: { memo: { status: 'synced', downloaded: 1291 }, ... } }
190+
```
191+
192+
## Storage Adapters
193+
194+
```ts
195+
import { MemoryStore } from '@ocash/sdk';
196+
import { IndexedDbStore } from '@ocash/sdk/browser';
197+
import { FileStore } from '@ocash/sdk/node';
198+
199+
new MemoryStore({ maxOperations: 100 })
200+
new IndexedDbStore({ dbName: 'myapp', maxOperations: 200 })
201+
new FileStore({ baseDir: './data', maxOperations: 500 })
202+
```
203+
204+
Required interface methods:
205+
- upsertUtxos(utxos: UtxoRecord[]): Promise<void>
206+
- listUtxos(query?: ListUtxosQuery): Promise<{ total: number; rows: UtxoRecord[] }>
207+
- markSpent(input: { chainId: number; nullifiers: Hex[] }): Promise<number>
208+
- getSyncCursor(chainId: number): Promise<SyncCursor | undefined>
209+
- setSyncCursor(chainId: number, cursor: SyncCursor): Promise<void>
210+
211+
## Events
212+
213+
All events via `onEvent` callback. Union type `SdkEvent`:
214+
215+
- core:ready — { assetsVersion, durationMs }
216+
- core:progress — { stage: 'fetch'|'compile'|'init', loaded, total? }
217+
- sync:start — { chainId }
218+
- sync:progress — { chainId, resource: 'memo'|'nullifier'|'merkle', downloaded, total? }
219+
- sync:done — { chainId, cursor }
220+
- wallet:utxo:update — { chainId, added, spent, frozen }
221+
- zkp:start — { circuit: 'transfer'|'withdraw' }
222+
- zkp:done — { circuit, costMs }
223+
- error — { code: SdkErrorCode, message, detail?, cause? }
224+
225+
Error codes: CONFIG | ASSETS | STORAGE | SYNC | CRYPTO | MERKLE | WITNESS | PROOF | RELAYER
226+
227+
## Key Types
228+
229+
```ts
230+
type Hex = `0x${string}`;
231+
232+
interface UtxoRecord {
233+
chainId: number; assetId: string; amount: bigint;
234+
commitment: Hex; nullifier: Hex; mkIndex: number;
235+
isFrozen: boolean; isSpent: boolean; memo?: Hex; createdAt?: number;
236+
}
237+
238+
interface CommitmentData {
239+
asset_id: bigint; asset_amount: bigint;
240+
user_pk: { user_address: [bigint, bigint] };
241+
blinding_factor: bigint; is_frozen: boolean;
242+
}
243+
244+
interface SyncCursor { memo: number; nullifier: number; merkle: number; }
245+
246+
type OperationType = 'deposit' | 'transfer' | 'withdraw';
247+
type OperationStatus = 'pending' | 'submitted' | 'confirmed' | 'failed';
248+
249+
interface ProofResult { proof: string; publicInputs: string[]; }
250+
interface RelayerRequest { kind: 'relayer'; method: 'POST'; path: string; body: Record<string, unknown>; }
251+
```
252+
253+
## Cryptography
254+
255+
- Curve: BabyJubjub (twisted Edwards over BN254 scalar field)
256+
- Hash: Poseidon2 (commitments, nullifiers, Merkle nodes)
257+
- Encryption: ECDH + NaCl XSalsa20-Poly1305 (memo encryption)
258+
- Key derivation: HKDF-SHA256 (seed → spending key)
259+
- Proofs: Groth16 zk-SNARK (Go WASM, transfer & withdraw circuits)
260+
- commitment = Poseidon2(asset_id, amount, pk.x, pk.y, blinding_factor)
261+
- nullifier = Poseidon2(commitment, secret_key, merkle_index)
262+
263+
## Static Utilities
264+
265+
```ts
266+
import { MemoKit, CryptoToolkit, KeyManager, Utils } from '@ocash/sdk';
267+
268+
MemoKit.createMemo(recordOpening) // Encrypt record opening → Hex memo
269+
MemoKit.decodeMemoForOwner({ secretKey, memo }) // Decrypt memo → CommitmentData | null
270+
271+
CryptoToolkit.commitment(data) // Poseidon2 commitment
272+
CryptoToolkit.nullifier(secretKey, commitment) // Nullifier derivation
273+
CryptoToolkit.createRecordOpening({ assetId, amount, userPk })
274+
275+
Utils.calcDepositFee(amount, feeBps) // Protocol fee calculation
276+
Utils.randomBytes32Bigint() // Cryptographic random bigint
277+
```

0 commit comments

Comments
 (0)