@orbinum/sdk 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  Official TypeScript SDK for Orbinum — a privacy-focused blockchain built on Substrate with an EVM compatibility layer.
4
4
 
5
- The SDK provides typed modules for interacting with the Orbinum protocol: Substrate RPC, EVM JSON-RPC, shielded pool operations, account identity and mapping, `rpc-v2`, ZK verifier, precompiles, and the indexer REST API.
6
-
7
5
  ## Installation
8
6
 
9
7
  ```bash
@@ -16,7 +14,6 @@ pnpm add @orbinum/sdk
16
14
 
17
15
  - Node.js 18 or later
18
16
  - A running Orbinum node (Substrate WebSocket endpoint)
19
- - An EVM JSON-RPC endpoint (optional, required for EVM and precompile operations)
20
17
 
21
18
  ## Quick Start
22
19
 
@@ -25,733 +22,27 @@ import { OrbinumClient } from '@orbinum/sdk';
25
22
 
26
23
  const client = await OrbinumClient.connect({
27
24
  substrateWs: 'ws://localhost:9944',
28
- evmRpc: 'http://localhost:9933',
29
- });
30
-
31
- const chainInfo = await client.substrate.getChainInfo();
32
- const root = await client.rpcV2.privacy.getMerkleRoot();
33
- const events = await client.substrate.queryBlockEvents('0xabc...');
34
- ```
35
-
36
- `OrbinumClient` wires together the SDK surface under a single interface.
37
-
38
- - `client.substrate`: Substrate WebSocket RPC, block queries, event decoding, and transaction helpers
39
- - `client.evm`: EVM JSON-RPC client, or `null` if `evmRpc` was not configured
40
- - `client.rpcV2`: typed Orbinum `rpc-v2` namespaces
41
- - `client.shieldedPool`: shielded-pool extrinsics and note helpers
42
- - `client.accountMapping`: alias, chain-link, metadata, and marketplace operations
43
- - `client.precompiles`: EVM precompile wrappers, or `null` if `evmRpc` was not configured
44
-
45
- Each module can also be instantiated independently.
46
-
47
- ## OrbinumClientProvider
48
-
49
- `OrbinumClientProvider` wraps `OrbinumClient` with automatic WebSocket reconnection, typed connection status events, and a React-friendly lifecycle.
50
-
51
- ```ts
52
- import { OrbinumClientProvider } from '@orbinum/sdk';
53
-
54
- const provider = new OrbinumClientProvider({
55
- substrateWs: 'ws://localhost:9944',
56
- evmRpc: 'http://localhost:9933',
25
+ evmRpc: 'http://localhost:9933', // optional
57
26
  });
58
27
 
59
- provider.on('statusChange', (event) => {
60
- console.log(event.status); // 'connecting' | 'connected' | 'disconnected' | 'error'
61
- });
62
-
63
- await provider.connect();
64
- const client = provider.client; // OrbinumClient once connected
65
- ```
66
-
67
- ## rpc-v2
68
-
69
- Orbinum's `rpc-v2` is organized by namespace.
70
-
71
- - Standard Frontier namespaces: `eth_*`, `net_*`, `web3_*`, `txpool_*`, `debug_*`
72
- - Orbinum-specific namespace: `privacy_*`
73
-
74
- In the SDK, `rpc-v2` is modeled as a dedicated top-level module, exposed through `client.rpcV2`. Each namespace lives under `src/rpc-v2/`.
75
-
76
- Current typed coverage:
77
-
78
- - `client.rpcV2.privacy.getMerkleRoot()`
79
- - `client.rpcV2.privacy.getMerkleProof(leafIndex)`
80
- - `client.rpcV2.privacy.getNullifierStatus(nullifier)`
81
- - `client.rpcV2.privacy.getPoolStats()`
82
-
83
- Example:
84
-
85
- ```ts
86
- const root = await client.rpcV2.privacy.getMerkleRoot();
87
-
88
- const proof = await client.rpcV2.privacy.getMerkleProof(12);
89
- // { path: string[]; leafIndex: number; treeDepth: number; }
90
-
91
- const status = await client.rpcV2.privacy.getNullifierStatus('0x...');
92
- // { nullifier: string; isSpent: boolean; }
93
-
94
- const stats = await client.rpcV2.privacy.getPoolStats();
95
- // { merkleRoot: string; commitmentCount: number; totalBalance: string; ... }
96
- ```
97
-
98
- Notes:
99
-
100
- - `rpc-v2` responses use `snake_case` from the node; the SDK normalizes them to `camelCase`.
101
- - `u128` values are exposed as decimal strings to avoid precision loss.
102
-
103
- ## Modules
104
-
105
- ### SubstrateClient
106
-
107
- Thin wrapper over [polkadot-api](https://github.com/polkadot-api/polkadot-api) (PAPI) for Substrate WebSocket communication.
108
-
109
- ```ts
110
- import { SubstrateClient } from '@orbinum/sdk';
111
-
112
- const substrate = await SubstrateClient.connect('ws://localhost:9944');
113
-
114
- const info = await substrate.getChainInfo();
115
- const health = await substrate.getHealth();
116
- const version = await substrate.getNodeVersion();
117
- const genesis = await substrate.getGenesisHash();
118
-
119
- // Block queries
120
- const header = await substrate.getBlockHeader('best');
121
- const hash = await substrate.getBlockHash(1000);
122
- const block = await substrate.getBlock('0xabc...');
123
-
124
- // Block events — decoded into EventRecord[]
125
- const events = await substrate.queryBlockEvents('0xabc...');
126
-
127
- // Block stream
128
- substrate.blocks$.subscribe(block => console.log(block.number));
129
-
130
- // Raw JSON-RPC call
131
- const result = await substrate.request('system_name', []);
132
-
133
- // Transaction helpers
134
- const tx = await substrate.txFromCallData(callBytes);
135
- const finalized = await tx.signAndSubmit(signer);
136
- const finalized2 = await substrate.submit(signedHex);
137
- substrate.submitAndWatch(signedHex).subscribe(event => console.log(event));
138
- ```
139
-
140
- ### EvmClient
141
-
142
- Stateless HTTP client following the Ethereum JSON-RPC specification.
143
-
144
- ```ts
145
- import { EvmClient } from '@orbinum/sdk';
146
-
147
- const evm = new EvmClient('http://localhost:9933');
148
-
149
- const balance = await evm.getBalance('0xYourAddress');
150
- const chainId = await evm.getChainId();
151
- const txHash = await evm.sendRawTransaction(signedHex);
152
-
153
- // Batch multiple calls in a single HTTP request
154
- const [bal, nonce] = await evm.batchRequest([
155
- { method: 'eth_getBalance', params: ['0xAddr', 'latest'] },
156
- { method: 'eth_getTransactionCount', params: ['0xAddr', 'latest'] },
157
- ]);
158
- ```
159
-
160
- ### EvmExplorer
161
-
162
- Read-only EVM block and transaction explorer.
163
-
164
- ```ts
165
- import { EvmExplorer } from '@orbinum/sdk';
166
-
167
- const explorer = new EvmExplorer('http://localhost:9933');
168
-
169
- const block = await explorer.getBlock(12345);
170
- const tx = await explorer.getTransaction('0xhash...');
171
- const logs = await explorer.getLogs({ fromBlock: 100, toBlock: 200, address: '0x...' });
172
- ```
173
-
174
- Types: `EvmBlock`, `EvmTransaction`, `EvmAddressInfo`, `EvmTxSummary`, `EvmLog`, `TokenInfo`, `TokenTransfer`.
175
-
176
- ### ZkVerifierModule
177
-
178
- Typed access to the on-chain ZK verifier — circuit version info, VK hashes, and version history.
179
-
180
- ```ts
181
- import { ZkVerifierModule } from '@orbinum/sdk';
182
-
183
- const zkv = new ZkVerifierModule(substrate);
184
-
185
- const info = await zkv.getCircuitVersionInfo('circuit-id');
186
- const vkHash = await zkv.getVkHash('circuit-id', 1);
187
- const stats = await zkv.getVersionStats('circuit-id');
188
- const history = await zkv.getHistoricalVersions('circuit-id');
189
- ```
190
-
191
- ### ShieldedPoolModule
192
-
193
- High-level interface for shielded pool extrinsics and note workflows. Requires a loaded `PrivacyKeyManager` and ZK proofs for unshield and private transfer.
194
-
195
- ```ts
196
- // Shield (deposit) tokens into the shielded pool
197
- const { txResult, note } = await client.shieldedPool.buildAndShield({
198
- amount: 1_000_000n,
199
- assetId: 1,
200
- tokenAddress: '0xTokenAddress',
201
- }, signer);
202
-
203
- // Private transfer between notes
204
- await client.shieldedPool.privateTransfer({ ...params }, signer);
205
-
206
- // Unshield (withdraw) tokens to a public address
207
- await client.shieldedPool.unshield({ ...params }, signer);
208
- ```
209
-
210
- ### PrivacyModule (`rpc-v2`)
211
-
212
- Typed wrapper for Orbinum `privacy_*` endpoints from `rpc-v2`.
213
-
214
- ```ts
215
- import { PrivacyModule } from '@orbinum/sdk';
216
-
217
- const privacy = new PrivacyModule(substrate);
218
-
219
- const merkleRoot = await privacy.getMerkleRoot();
220
- const merkleProof = await privacy.getMerkleProof(4);
221
- const nullifier = await privacy.getNullifierStatus('0xNullifier');
222
- const stats = await privacy.getPoolStats();
223
- ```
224
-
225
- ### Privacy Keys
226
-
227
- Key derivation follows a deterministic chain from the user's wallet signature. No key material is ever stored by the SDK.
228
-
229
- ```ts
230
- import {
231
- PrivacyKeyManager,
232
- deriveOwnerPk,
233
- deriveSpendingKeyFromSignature,
234
- deriveSpendingKeyMessage,
235
- deriveViewingKey,
236
- } from '@orbinum/sdk';
237
-
238
- const message = deriveSpendingKeyMessage(chainId, evmAddress);
239
- const spendingKey = deriveSpendingKeyFromSignature(sigHex, chainId, evmAddress);
240
-
241
- const keyManager = new PrivacyKeyManager();
242
- keyManager.load(spendingKey);
243
-
244
- const viewingKey = deriveViewingKey(spendingKey);
245
- const ownerPk = deriveOwnerPk(spendingKey);
246
- ```
247
-
248
- ### AccountMappingModule
249
-
250
- Manage on-chain identity by linking Substrate and EVM accounts, registering aliases, and interacting with the alias marketplace.
251
-
252
- ```ts
253
- await client.accountMapping.registerAlias({ alias: 'myalias' }, signer);
254
- await client.accountMapping.addChainLink({ chainId: 1, address: '0xEvmAddr' }, signer);
255
-
256
- const alias = await client.accountMapping.getAliasOf(substrateHex);
257
- const linked = await client.accountMapping.getChainLinks(substrateHex);
258
- ```
259
-
260
- ### IndexerClient
261
-
262
- HTTP client for the Orbinum indexer REST API. All list endpoints are paginated.
263
-
264
- ```ts
265
- import { IndexerClient } from '@orbinum/sdk';
266
-
267
- const indexer = new IndexerClient({ baseUrl: 'https://indexer.orbinum.io' });
268
-
269
- const blocks = await indexer.getBlocks({ page: 1, limit: 20 });
270
- const extrinsics = await indexer.getExtrinsics({ address: '5F...' });
271
- const commitments = await indexer.getCommitments({ page: 1, limit: 20 });
272
- const nullifier = await indexer.getNullifierStatus('0xNullifier');
273
- const roots = await indexer.getMerkleRoots({ limit: 10 });
274
- const evmTxs = await indexer.getEvmTransactions({ address: '0xabc...' });
275
- const stats = await indexer.getStats();
276
- ```
277
-
278
- ### Precompiles
279
-
280
- Typed wrappers for Orbinum's EVM precompile contracts.
281
-
282
- | Precompile | Address | Description |
283
- |---|---|---|
284
- | `ShieldedPoolPrecompile` | `0x0801` | Shield, unshield, and private transfer from EVM |
285
- | `AccountMappingPrecompile` | `0x0800` | Identity and alias operations from EVM |
286
- | `CryptoPrecompiles` | `0x0400–0x0403` | Frontier crypto utilities |
287
-
288
- ```ts
289
- import { ShieldedPoolPrecompile, decodePrecompileCalldata } from '@orbinum/sdk';
290
-
291
- const precompile = new ShieldedPoolPrecompile(evmClient);
292
- await precompile.shield(amount, tokenAddress, commitment, walletSigner);
293
-
294
- // Decode raw EVM calldata for a known precompile
295
- const decoded = decodePrecompileCalldata('0x0800', calldata);
296
- ```
297
-
298
- ## Extrinsic & Event Decoders
299
-
300
- The `mapExtrinsicArgs` and `mapZkEventData` helpers decode raw pallet call data from the indexer or block scanner into typed objects.
301
-
302
- ```ts
303
- import { mapExtrinsicArgs, mapZkEventData } from '@orbinum/sdk';
304
-
305
- const decoded = mapExtrinsicArgs('shieldedPool', 'shield', rawArgs);
306
- // DecodedShieldArgs | DecodedUnshieldArgs | ...
307
-
308
- const eventData = mapZkEventData('ProofVerified', rawEventData);
309
- ```
310
-
311
- ## Substrate SCALE Primitives
312
-
313
- SCALE codec primitives from `@polkadot-api/substrate-bindings` are re-exported directly from the SDK. There is no need to install that package separately.
314
-
315
- ```ts
316
- import { Blake2256, AccountId, u128, u64, Storage, Keccak256 } from '@orbinum/sdk';
317
- import { base58, getSs58AddressInfo } from '@orbinum/sdk';
318
- ```
319
-
320
- ## Key Derivation Chain
321
-
322
- ```
323
- wallet.sign(message)
324
- |
325
- v
326
- deriveSpendingKeyFromSignature() -- HKDF-SHA256 over signature bytes, mod BN254_R
327
- |
328
- +-- deriveViewingKey() -- HKDF-SHA256 -> 32-byte ChaCha20 symmetric key
329
- | (used to encrypt/decrypt note memos)
330
- |
331
- +-- deriveOwnerPk() -- BabyJubJub scalar multiplication -> Ax
332
- (embedded in shielded note commitments)
333
- ```
334
-
335
- ## Development
336
-
337
- ### Typing Layout
338
-
339
- The SDK organizes types by feature ownership.
340
-
341
- - `types/index.ts`: public shared types of the feature
342
- - `types/pallet-events.ts`: event payloads and discriminated unions for that pallet
343
- - `types/pallet-extrinsics.ts`: extrinsic argument types and call unions for that pallet
344
- - `types/raw.ts`: internal node or RPC response shapes used only for transport mapping
345
-
346
- Examples:
347
-
348
- - `src/shielded-pool/types/index.ts`
349
- - `src/shielded-pool/types/pallet-events.ts`
350
- - `src/shielded-pool/types/pallet-extrinsics.ts`
351
- - `src/rpc-v2/types/raw.ts`
352
- - `src/indexer/types/index.ts`
353
- - `src/account-mapping/types/index.ts`
354
-
355
- Rules:
356
-
357
- 1. If a type is part of the public API of a feature, keep it in that feature's `types/index.ts`.
358
- 2. If a type only mirrors a transport payload from RPC, keep it in `types/raw.ts`.
359
- 3. Do not reintroduce a global `src/types.ts` or `src/types/` directory.
360
- 4. Export public types from `src/index.ts`, but keep ownership at the feature level.
361
-
362
- ### Extending `rpc-v2`
363
-
364
- The intended extension pattern is namespace-oriented and centralized under `RpcV2Module`.
365
-
366
- For example, to add `net_*` support:
367
-
368
- 1. Create `src/rpc-v2/NetModule.ts`
369
- 2. Define raw response types that match the node's JSON exactly
370
- 3. Map raw `snake_case` or hex-shaped values into stable SDK-facing TypeScript types
371
- 4. Export the module from `src/rpc-v2/index.ts`
372
- 5. Attach it in `RpcV2Module`, for example as `client.rpcV2.net`
373
- 6. Add unit tests that verify RPC method names, params, and response mapping
374
-
375
- ```ts
376
- export class NetModule {
377
- constructor(private readonly substrate: SubstrateClient) {}
378
-
379
- async version(): Promise<string> {
380
- return this.substrate.request<string>('net_version', []);
381
- }
382
- }
28
+ const info = await client.substrate.getChainInfo();
29
+ const root = await client.rpcV2.privacy.getMerkleRoot();
30
+ const block = await client.substrate.getBlock('best');
383
31
  ```
384
32
 
385
- ### Commands
33
+ `OrbinumClient` exposes the following modules:
386
34
 
387
- ```bash
388
- pnpm install
389
- pnpm build # compile to dist/ (ESM + CJS + types)
390
- pnpm test # run test suite (769 tests)
391
- pnpm typecheck:all # typecheck src and tests
392
- pnpm lint # eslint
393
- pnpm format # prettier
394
- ```
35
+ | Property | Description |
36
+ |---|---|
37
+ | `client.substrate` | Substrate RPC blocks, events, transactions |
38
+ | `client.evm` | EVM JSON-RPC client (`null` if `evmRpc` not set) |
39
+ | `client.rpcV2` | Orbinum `rpc-v2` namespaces (`privacy_*`, etc.) |
40
+ | `client.shieldedPool` | Shielded pool extrinsics |
41
+ | `client.accountMapping` | Alias, chain-link, and identity operations |
42
+ | `client.precompiles` | EVM precompile wrappers (`null` if `evmRpc` not set) |
395
43
 
396
- ## License
397
-
398
- ISC
399
-
400
-
401
- ## Installation
402
-
403
- ```bash
404
- npm install @orbinum/sdk
405
- # or
406
- pnpm add @orbinum/sdk
407
- ```
408
-
409
- ## Requirements
410
-
411
- - Node.js 18 or later
412
- - A running Orbinum node (Substrate WebSocket endpoint)
413
- - An EVM JSON-RPC endpoint (optional, required for EVM and precompile operations)
414
-
415
- ## Quick Start
416
-
417
- ```ts
418
- import { OrbinumClient } from '@orbinum/sdk';
419
-
420
- const client = await OrbinumClient.connect({
421
- substrateWs: 'ws://localhost:9944',
422
- evmRpc: 'http://localhost:9933',
423
- });
424
-
425
- const chainInfo = await client.substrate.getChainInfo();
426
- const root = await client.rpcV2.privacy.getMerkleRoot();
427
- const tree = await client.shieldedPool.merkle.getTreeInfo();
428
- ```
429
-
430
- `OrbinumClient` wires together the current SDK surface under a single interface.
431
-
432
- - `client.substrate`: Substrate WebSocket RPC and transaction helpers
433
- - `client.evm`: EVM JSON-RPC client, or `null` if `evmRpc` was not configured
434
- - `client.rpcV2`: typed Orbinum `rpc-v2` namespaces
435
- - `client.shieldedPool`: shielded-pool extrinsics, note helpers, and Merkle queries
436
- - `client.accountMapping`: alias, chain-link, metadata, and marketplace operations
437
- - `client.precompiles`: EVM precompile wrappers, or `null` if `evmRpc` was not configured
438
-
439
- Each module can also be instantiated independently.
440
-
441
- ## rpc-v2
442
-
443
- Orbinum's `rpc-v2` is organized by namespace.
444
-
445
- - Standard Frontier namespaces: `eth_*`, `net_*`, `web3_*`, `txpool_*`, `debug_*`
446
- - Orbinum-specific namespace: `privacy_*`
447
-
448
- In the SDK, `rpc-v2` is modeled as a dedicated top-level module, exposed through `client.rpcV2`. Each namespace lives under `src/rpc-v2/` and is grouped there instead of being mixed into legacy protocol modules.
449
-
450
- Current typed coverage:
451
-
452
- - `client.rpcV2.privacy.getMerkleRoot()`
453
- - `client.rpcV2.privacy.getMerkleProof(leafIndex)`
454
- - `client.rpcV2.privacy.getNullifierStatus(nullifier)`
455
- - `client.rpcV2.privacy.getPoolStats()`
456
-
457
- Example:
458
-
459
- ```ts
460
- const root = await client.rpcV2.privacy.getMerkleRoot();
461
-
462
- const proof = await client.rpcV2.privacy.getMerkleProof(12);
463
- // {
464
- // path: string[];
465
- // leafIndex: number;
466
- // treeDepth: number;
467
- // }
468
-
469
- const status = await client.rpcV2.privacy.getNullifierStatus('0x...');
470
- // {
471
- // nullifier: string;
472
- // isSpent: boolean;
473
- // }
474
-
475
- const stats = await client.rpcV2.privacy.getPoolStats();
476
- // {
477
- // merkleRoot: string;
478
- // commitmentCount: number;
479
- // totalBalance: string;
480
- // assetBalances: { assetId: number; balance: string }[];
481
- // treeDepth: number;
482
- // }
483
- ```
484
-
485
- Notes:
486
-
487
- - `rpc-v2` responses from the node use `snake_case`; the SDK maps them to `camelCase`.
488
- - `u128` values are exposed as decimal strings to avoid precision loss in JavaScript.
489
- - Privacy queries belong to `client.rpcV2.privacy.*`; they are no longer described as part of `ShieldedPoolModule`.
490
-
491
- ## Modules
492
-
493
- ### SubstrateClient
494
-
495
- Thin wrapper over [polkadot-api](https://github.com/polkadot-api/polkadot-api) (PAPI) for Substrate WebSocket communication.
496
-
497
- ```ts
498
- import { SubstrateClient } from '@orbinum/sdk';
499
-
500
- const substrate = await SubstrateClient.connect('ws://localhost:9944');
501
-
502
- const info = await substrate.getChainInfo();
503
- const health = await substrate.getHealth();
504
- const version = await substrate.getNodeVersion();
505
- const genesis = await substrate.getGenesisHash();
506
-
507
- // Raw JSON-RPC call
508
- const result = await substrate.request('system_name', []);
509
-
510
- // Build a transaction from pre-encoded SCALE call bytes
511
- const tx = await substrate.txFromCallData(callBytes);
512
- const finalized = await tx.signAndSubmit(signer);
513
-
514
- // Submit a pre-signed extrinsic
515
- const finalized = await substrate.submit(signedHex);
516
-
517
- // Submit and observe lifecycle events
518
- substrate.submitAndWatch(signedHex).subscribe(event => console.log(event));
519
- ```
520
-
521
- ### EvmClient
522
-
523
- Stateless HTTP client following the Ethereum JSON-RPC specification.
524
-
525
- ```ts
526
- import { EvmClient } from '@orbinum/sdk';
527
-
528
- const evm = new EvmClient('http://localhost:9933');
529
-
530
- const balance = await evm.getBalance('0xYourAddress');
531
- const chainId = await evm.getChainId();
532
- const txHash = await evm.sendRawTransaction(signedHex);
533
-
534
- // Batch multiple calls in a single HTTP request
535
- const [balance, nonce] = await evm.batchRequest([
536
- { method: 'eth_getBalance', params: ['0xAddr', 'latest'] },
537
- { method: 'eth_getTransactionCount', params: ['0xAddr', 'latest'] },
538
- ]);
539
- ```
540
-
541
- ### RpcV2Module
542
-
543
- Top-level typed entry point for Orbinum `rpc-v2` namespaces.
544
-
545
- ```ts
546
- const root = await client.rpcV2.privacy.getMerkleRoot();
547
- const proof = await client.rpcV2.privacy.getMerkleProof(4);
548
- const nullifier = await client.rpcV2.privacy.getNullifierStatus('0xNullifier');
549
- const stats = await client.rpcV2.privacy.getPoolStats();
550
- ```
551
-
552
- ### ShieldedPoolModule
553
-
554
- High-level interface for shielded pool extrinsics and note workflows. Requires a loaded `PrivacyKeyManager` and ZK proofs for unshield and private transfer.
555
-
556
- ```ts
557
- // Shield (deposit) tokens into the shielded pool
558
- const { txResult, note } = await client.shieldedPool.buildAndShield({
559
- amount: 1_000_000n,
560
- assetId: 1,
561
- tokenAddress: '0xTokenAddress',
562
- }, signer);
563
-
564
- const treeInfo = await client.shieldedPool.merkle.getTreeInfo();
565
-
566
- // Private transfer between notes
567
- await client.shieldedPool.privateTransfer({ ...params }, signer);
568
-
569
- // Unshield (withdraw) tokens to a public address
570
- await client.shieldedPool.unshield({ ...params }, signer);
571
-
572
- ```
573
-
574
- ### PrivacyModule (`rpc-v2`)
575
-
576
- Typed wrapper for Orbinum `privacy_*` endpoints from `rpc-v2`.
577
-
578
- ```ts
579
- import { PrivacyModule } from '@orbinum/sdk';
580
-
581
- const privacy = new PrivacyModule(client.substrate);
582
-
583
- const merkleRoot = await privacy.getMerkleRoot();
584
- const merkleProof = await privacy.getMerkleProof(4);
585
- const nullifier = await privacy.getNullifierStatus('0xNullifier');
586
- const stats = await privacy.getPoolStats();
587
- ```
588
-
589
- ### Privacy Keys
590
-
591
- Key derivation follows a deterministic chain from the user's wallet signature. No key material is ever stored by the SDK.
592
-
593
- ```ts
594
- import {
595
- PrivacyKeyManager,
596
- deriveOwnerPk,
597
- deriveSpendingKeyFromSignature,
598
- deriveSpendingKeyMessage,
599
- deriveViewingKey,
600
- } from '@orbinum/sdk';
601
-
602
- // 1. Get the message the user must sign
603
- const message = deriveSpendingKeyMessage(chainId, evmAddress);
604
-
605
- // 2. Derive the spending key from the wallet signature
606
- const spendingKey = deriveSpendingKeyFromSignature(sigHex, chainId, evmAddress);
607
-
608
- // 3. Load into the key manager
609
- const keyManager = new PrivacyKeyManager();
610
- keyManager.load(spendingKey);
611
-
612
- // The manager derives the viewing key (ChaCha20 memo decryption)
613
- // and owner public key (BabyJubJub, used in note commitments)
614
- const viewingKey = deriveViewingKey(spendingKey);
615
- const ownerPk = deriveOwnerPk(spendingKey);
616
- ```
617
-
618
- ### AccountMappingModule
619
-
620
- Manage on-chain identity by linking Substrate and EVM accounts, registering aliases, and interacting with the alias marketplace.
621
-
622
- ```ts
623
- // Register an alias
624
- await client.accountMapping.registerAlias({ alias: 'myalias' }, signer);
625
-
626
- // Link an EVM address to a Substrate account
627
- await client.accountMapping.addChainLink({ chainId: 1, address: '0xEvmAddr' }, signer);
628
-
629
- // Query
630
- const alias = await client.accountMapping.getAliasOf(substrateHex);
631
- const linked = await client.accountMapping.getChainLinks(substrateHex);
632
- ```
633
-
634
- ### IndexerClient
635
-
636
- HTTP client for the Orbinum indexer REST API. The indexer runs as a separate service indexed from node events.
637
-
638
- ```ts
639
- import { IndexerClient } from '@orbinum/sdk';
640
-
641
- const indexer = new IndexerClient({
642
- baseUrl: 'https://indexer.orbinum.io',
643
- });
644
-
645
- const commitments = await indexer.getCommitments({ page: 1, limit: 20 });
646
- const status = await indexer.getNullifierStatus('0xNullifier');
647
- const roots = await indexer.getMerkleRoots({ limit: 10 });
648
- const extrinsics = await indexer.getAddressExtrinsics('5F...');
649
- const evmTxs = await indexer.getEvmTransactions({ address: '0xabc...' });
650
- ```
651
-
652
- ### Precompiles
653
-
654
- Typed wrappers for Orbinum's EVM precompile contracts, callable from any EVM wallet or signer.
655
-
656
- | Precompile | Address | Description |
657
- |---|---|---|
658
- | `ShieldedPoolPrecompile` | `0x0801` | Shield, unshield, and private transfer from EVM |
659
- | `AccountMappingPrecompile` | `0x0800` | Identity and alias operations from EVM |
660
- | `CryptoPrecompiles` | `0x0400–0x0403` | Frontier crypto utilities (SHA3, EC recover, Curve25519) |
661
-
662
- ```ts
663
- import { ShieldedPoolPrecompile } from '@orbinum/sdk';
664
-
665
- const precompile = new ShieldedPoolPrecompile(evmClient);
666
- await precompile.shield(amount, tokenAddress, commitment, walletSigner);
667
- ```
668
-
669
- ## Key Derivation Chain
670
-
671
- ```
672
- wallet.sign(message)
673
- |
674
- v
675
- deriveSpendingKeyFromSignature() -- HKDF-SHA256 over signature bytes, mod BN254_R
676
- |
677
- +-- deriveViewingKey() -- HKDF-SHA256 -> 32-byte ChaCha20 symmetric key
678
- | (used to encrypt/decrypt note memos)
679
- |
680
- +-- deriveOwnerPk() -- BabyJubJub scalar multiplication -> Ax
681
- (embedded in shielded note commitments)
682
- ```
683
-
684
- ## Development
685
-
686
- ### Typing Layout
687
-
688
- The SDK organizes types by feature ownership.
689
-
690
- - `types/index.ts`: public shared types of the feature
691
- - `types/pallet-events.ts`: event payloads and discriminated unions for that pallet
692
- - `types/pallet-extrinsics.ts`: extrinsic argument types and call unions for that pallet
693
- - `types/raw.ts`: internal node or RPC response shapes used only for transport mapping
694
-
695
- Examples:
696
-
697
- - `src/shielded-pool/types/index.ts`
698
- - `src/shielded-pool/types/pallet-events.ts`
699
- - `src/shielded-pool/types/pallet-extrinsics.ts`
700
- - `src/rpc-v2/types/raw.ts`
701
- - `src/indexer/types/index.ts`
702
- - `src/precompiles/types/index.ts`
703
-
704
- Rules:
705
-
706
- 1. If a type is part of the public API of a feature, keep it in that feature's `types/index.ts`.
707
- 2. If a type only mirrors a transport payload from RPC, keep it in `types/raw.ts`.
708
- 3. Do not reintroduce a global `src/types.ts` or `src/types/` directory.
709
- 4. Export public types from `src/index.ts`, but keep ownership at the feature level.
710
-
711
- ### Extending `rpc-v2`
712
-
713
- The intended extension pattern is namespace-oriented and centralized under `RpcV2Module`.
714
-
715
- For example, to add `net_*` support:
716
-
717
- 1. Create `src/rpc-v2/NetModule.ts`
718
- 2. Define raw response types that match the node's JSON exactly
719
- 3. Map raw `snake_case` or hex-shaped values into stable SDK-facing TypeScript types
720
- 4. Export the module from `src/rpc-v2/index.ts`
721
- 5. Attach it in `RpcV2Module`, for example as `client.rpcV2.net`
722
- 6. Add unit tests that verify RPC method names, params, and response mapping
723
-
724
- Minimal shape example:
725
-
726
- ```ts
727
- export class NetModule {
728
- constructor(private readonly substrate: SubstrateClient) {}
729
-
730
- async version(): Promise<string> {
731
- return this.substrate.request<string>('net_version', []);
732
- }
733
-
734
- async peerCount(): Promise<string> {
735
- return this.substrate.request<string>('net_peerCount', []);
736
- }
737
-
738
- async listening(): Promise<boolean> {
739
- return this.substrate.request<boolean>('net_listening', []);
740
- }
741
- }
742
- ```
743
-
744
- The same approach applies to `web3_*`, `txpool_*`, `eth_*`, and any future Orbinum-specific namespaces.
745
-
746
- ```bash
747
- pnpm install
748
- pnpm build # compile to dist/ (ESM + CJS + types)
749
- pnpm test # run test suite
750
- pnpm typecheck:all # typecheck src and tests
751
- pnpm lint # eslint
752
- pnpm format # prettier
753
- ```
44
+ Each module can also be instantiated independently without `OrbinumClient`.
754
45
 
755
46
  ## License
756
47
 
757
- ISC
48
+ MIT