navio-sdk 0.1.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 +758 -0
- package/dist/index.d.mts +2500 -0
- package/dist/index.d.ts +2500 -0
- package/dist/index.js +5050 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5002 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +77 -0
package/README.md
ADDED
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
# Navio SDK
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for interacting with the Navio blockchain. Provides wallet management, transaction key synchronization, BLSCT confidential transaction support, and blockchain interaction through Electrum servers or P2P connections.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Wallet Management** - HD key derivation with BLS CT support
|
|
8
|
+
- **Dual Sync Backends** - Electrum protocol or direct P2P node connections
|
|
9
|
+
- **Automatic Output Detection** - BLSCT output scanning with view tag optimization
|
|
10
|
+
- **Amount Recovery** - Decrypt confidential transaction amounts
|
|
11
|
+
- **Balance Tracking** - Query wallet balance and UTXOs
|
|
12
|
+
- **Spending Status Tracking** - Monitor spent/unspent outputs
|
|
13
|
+
- **Blockchain Reorganization Handling** - Automatic reorg detection and recovery
|
|
14
|
+
- **Cross-Platform Persistence** - SQLite via SQL.js (browser, Node.js, mobile)
|
|
15
|
+
- **Hierarchical Deterministic Sub-addresses** - Multiple account support
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install navio-sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { NavioClient } from 'navio-sdk';
|
|
27
|
+
|
|
28
|
+
// Create and initialize client
|
|
29
|
+
const client = new NavioClient({
|
|
30
|
+
walletDbPath: './my-wallet.db',
|
|
31
|
+
backend: 'electrum', // or 'p2p'
|
|
32
|
+
electrum: {
|
|
33
|
+
host: 'localhost',
|
|
34
|
+
port: 50005,
|
|
35
|
+
ssl: false,
|
|
36
|
+
},
|
|
37
|
+
network: 'mainnet', // 'mainnet' | 'testnet' | 'signet' | 'regtest'
|
|
38
|
+
createWalletIfNotExists: true,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Initialize (loads wallet, connects to backend)
|
|
42
|
+
await client.initialize();
|
|
43
|
+
|
|
44
|
+
// Sync transaction keys
|
|
45
|
+
await client.sync({
|
|
46
|
+
onProgress: (height, tip, blocks, txKeys) => {
|
|
47
|
+
console.log(`Syncing: ${height}/${tip} (${blocks} blocks, ${txKeys} TX keys)`);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Check wallet balance
|
|
52
|
+
const balance = await client.getBalanceNav();
|
|
53
|
+
console.log(`Balance: ${balance} NAV`);
|
|
54
|
+
|
|
55
|
+
// Get unspent outputs
|
|
56
|
+
const utxos = await client.getUnspentOutputs();
|
|
57
|
+
console.log(`UTXOs: ${utxos.length}`);
|
|
58
|
+
|
|
59
|
+
// Access wallet operations
|
|
60
|
+
const keyManager = client.getKeyManager();
|
|
61
|
+
const subAddress = keyManager.getSubAddress({ account: 0, address: 0 });
|
|
62
|
+
console.log('Sub-address:', subAddress.toString());
|
|
63
|
+
|
|
64
|
+
// Cleanup
|
|
65
|
+
await client.disconnect();
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
### NavioClientConfig
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
interface NavioClientConfig {
|
|
74
|
+
// Required
|
|
75
|
+
walletDbPath: string; // Path to wallet database file
|
|
76
|
+
|
|
77
|
+
// Backend selection (default: 'electrum')
|
|
78
|
+
backend?: 'electrum' | 'p2p';
|
|
79
|
+
|
|
80
|
+
// Electrum backend options
|
|
81
|
+
electrum?: {
|
|
82
|
+
host?: string; // Server host (default: 'localhost')
|
|
83
|
+
port?: number; // Server port (default: 50001)
|
|
84
|
+
ssl?: boolean; // Use SSL/TLS (default: false)
|
|
85
|
+
timeout?: number; // Request timeout ms (default: 30000)
|
|
86
|
+
clientName?: string; // Client name (default: 'navio-sdk')
|
|
87
|
+
clientVersion?: string; // Protocol version (default: '1.4')
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// P2P backend options
|
|
91
|
+
p2p?: {
|
|
92
|
+
host: string; // Node host
|
|
93
|
+
port: number; // Node port (mainnet: 33670, testnet: 43670)
|
|
94
|
+
network: 'mainnet' | 'testnet'; // Network type
|
|
95
|
+
debug?: boolean; // Enable debug logging
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Network configuration (for navio-blsct)
|
|
99
|
+
network?: 'mainnet' | 'testnet' | 'signet' | 'regtest';
|
|
100
|
+
|
|
101
|
+
// Wallet options
|
|
102
|
+
createWalletIfNotExists?: boolean; // Create wallet if missing (default: false)
|
|
103
|
+
restoreFromSeed?: string; // Restore from seed (hex string)
|
|
104
|
+
restoreFromHeight?: number; // Block height when wallet was created (for restore)
|
|
105
|
+
creationHeight?: number; // Creation height for new wallets (default: chainTip - 100)
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## API Reference
|
|
110
|
+
|
|
111
|
+
### NavioClient
|
|
112
|
+
|
|
113
|
+
Main client class for wallet operations and blockchain synchronization.
|
|
114
|
+
|
|
115
|
+
#### Constructor
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const client = new NavioClient(config: NavioClientConfig);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### Initialization
|
|
122
|
+
|
|
123
|
+
##### `initialize(): Promise<void>`
|
|
124
|
+
|
|
125
|
+
Initializes the client:
|
|
126
|
+
- Loads or creates wallet from database
|
|
127
|
+
- Connects to backend (Electrum/P2P)
|
|
128
|
+
- Initializes sync manager
|
|
129
|
+
- Sets up KeyManager for output detection
|
|
130
|
+
|
|
131
|
+
#### Synchronization
|
|
132
|
+
|
|
133
|
+
##### `sync(options?: SyncOptions): Promise<number>`
|
|
134
|
+
|
|
135
|
+
Synchronizes transaction keys from the blockchain.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
interface SyncOptions {
|
|
139
|
+
startHeight?: number; // Start height (default: last synced + 1)
|
|
140
|
+
endHeight?: number; // End height (default: chain tip)
|
|
141
|
+
onProgress?: (
|
|
142
|
+
currentHeight: number,
|
|
143
|
+
chainTip: number,
|
|
144
|
+
blocksProcessed: number,
|
|
145
|
+
txKeysProcessed: number,
|
|
146
|
+
isReorg: boolean
|
|
147
|
+
) => void;
|
|
148
|
+
stopOnReorg?: boolean; // Stop on reorg (default: true)
|
|
149
|
+
verifyHashes?: boolean; // Verify block hashes (default: true)
|
|
150
|
+
saveInterval?: number; // Save every N blocks (default: 100)
|
|
151
|
+
keepTxKeys?: boolean; // Keep TX keys in DB (default: false)
|
|
152
|
+
blockHashRetention?: number; // Keep last N hashes (default: 10000)
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Returns: Number of transaction keys synced
|
|
157
|
+
|
|
158
|
+
##### `isSyncNeeded(): Promise<boolean>`
|
|
159
|
+
|
|
160
|
+
Checks if synchronization is needed.
|
|
161
|
+
|
|
162
|
+
##### `getLastSyncedHeight(): number`
|
|
163
|
+
|
|
164
|
+
Returns the last synced block height, or -1 if never synced.
|
|
165
|
+
|
|
166
|
+
##### `getSyncState(): SyncState`
|
|
167
|
+
|
|
168
|
+
Returns current sync state with statistics.
|
|
169
|
+
|
|
170
|
+
#### Background Sync
|
|
171
|
+
|
|
172
|
+
##### `startBackgroundSync(options?: BackgroundSyncOptions): Promise<void>`
|
|
173
|
+
|
|
174
|
+
Start continuous background synchronization. The client will poll for new blocks
|
|
175
|
+
and automatically sync. Callbacks are invoked for new blocks, transactions, and balance changes.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
interface BackgroundSyncOptions extends SyncOptions {
|
|
179
|
+
pollInterval?: number; // Polling interval in ms (default: 10000)
|
|
180
|
+
onNewBlock?: (height: number, hash: string) => void;
|
|
181
|
+
onNewTransaction?: (txHash: string, outputHash: string, amount: bigint) => void;
|
|
182
|
+
onBalanceChange?: (newBalance: bigint, oldBalance: bigint) => void;
|
|
183
|
+
onError?: (error: Error) => void;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
##### `stopBackgroundSync(): void`
|
|
188
|
+
|
|
189
|
+
Stop background synchronization.
|
|
190
|
+
|
|
191
|
+
##### `isBackgroundSyncActive(): boolean`
|
|
192
|
+
|
|
193
|
+
Check if background sync is running.
|
|
194
|
+
|
|
195
|
+
#### Balance & Outputs
|
|
196
|
+
|
|
197
|
+
##### `getBalance(tokenId?: string | null): Promise<bigint>`
|
|
198
|
+
|
|
199
|
+
Get wallet balance in satoshis.
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// NAV balance
|
|
203
|
+
const balanceSats = await client.getBalance();
|
|
204
|
+
|
|
205
|
+
// Token balance
|
|
206
|
+
const tokenBalance = await client.getBalance('token-id-hex');
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
##### `getBalanceNav(tokenId?: string | null): Promise<number>`
|
|
210
|
+
|
|
211
|
+
Get wallet balance in NAV (with 8 decimal places).
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
const balance = await client.getBalanceNav();
|
|
215
|
+
console.log(`Balance: ${balance.toFixed(8)} NAV`);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
##### `getUnspentOutputs(tokenId?: string | null): Promise<WalletOutput[]>`
|
|
219
|
+
|
|
220
|
+
Get unspent outputs (UTXOs).
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
interface WalletOutput {
|
|
224
|
+
outputHash: string;
|
|
225
|
+
txHash: string;
|
|
226
|
+
outputIndex: number;
|
|
227
|
+
blockHeight: number;
|
|
228
|
+
amount: bigint;
|
|
229
|
+
memo: string | null;
|
|
230
|
+
tokenId: string | null;
|
|
231
|
+
blindingKey: string;
|
|
232
|
+
spendingKey: string;
|
|
233
|
+
isSpent: boolean;
|
|
234
|
+
spentTxHash: string | null;
|
|
235
|
+
spentBlockHeight: number | null;
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
##### `getAllOutputs(): Promise<WalletOutput[]>`
|
|
240
|
+
|
|
241
|
+
Get all wallet outputs (spent and unspent).
|
|
242
|
+
|
|
243
|
+
#### Accessors
|
|
244
|
+
|
|
245
|
+
##### `getKeyManager(): KeyManager`
|
|
246
|
+
|
|
247
|
+
Returns the KeyManager instance for wallet operations.
|
|
248
|
+
|
|
249
|
+
##### `getWalletDB(): WalletDB`
|
|
250
|
+
|
|
251
|
+
Returns the WalletDB instance for database operations.
|
|
252
|
+
|
|
253
|
+
##### `getSyncProvider(): SyncProvider`
|
|
254
|
+
|
|
255
|
+
Returns the current sync provider (Electrum or P2P).
|
|
256
|
+
|
|
257
|
+
##### `getSyncManager(): TransactionKeysSync`
|
|
258
|
+
|
|
259
|
+
Returns the TransactionKeysSync instance for sync operations.
|
|
260
|
+
|
|
261
|
+
##### `getBackendType(): 'electrum' | 'p2p'`
|
|
262
|
+
|
|
263
|
+
Returns the current backend type.
|
|
264
|
+
|
|
265
|
+
##### `getNetwork(): string`
|
|
266
|
+
|
|
267
|
+
Returns the configured network.
|
|
268
|
+
|
|
269
|
+
##### `isConnected(): boolean`
|
|
270
|
+
|
|
271
|
+
Check if client is connected to the backend.
|
|
272
|
+
|
|
273
|
+
#### Connection
|
|
274
|
+
|
|
275
|
+
##### `connect(): Promise<void>`
|
|
276
|
+
|
|
277
|
+
Connect to the backend.
|
|
278
|
+
|
|
279
|
+
##### `disconnect(): Promise<void>`
|
|
280
|
+
|
|
281
|
+
Disconnect from backend and close database.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
### KeyManager
|
|
286
|
+
|
|
287
|
+
Manages BLS CT keys, sub-addresses, and output detection.
|
|
288
|
+
|
|
289
|
+
#### Key Generation
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// Generate new seed
|
|
293
|
+
const seed = keyManager.generateNewSeed();
|
|
294
|
+
|
|
295
|
+
// Set HD seed
|
|
296
|
+
keyManager.setHDSeed(seed);
|
|
297
|
+
|
|
298
|
+
// Get master seed (for backup)
|
|
299
|
+
const masterSeed = keyManager.getMasterSeedKey();
|
|
300
|
+
console.log('Seed:', masterSeed.serialize()); // hex string
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
#### Sub-addresses
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
// Get sub-address by identifier
|
|
307
|
+
const subAddr = keyManager.getSubAddress({ account: 0, address: 0 });
|
|
308
|
+
|
|
309
|
+
// Generate new sub-address
|
|
310
|
+
const { subAddress, id } = keyManager.generateNewSubAddress(0); // account 0
|
|
311
|
+
|
|
312
|
+
// Create sub-address pool
|
|
313
|
+
keyManager.newSubAddressPool(0); // Main account
|
|
314
|
+
keyManager.newSubAddressPool(-1); // Change
|
|
315
|
+
keyManager.newSubAddressPool(-2); // Staking
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### Output Detection
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
// Check if output belongs to wallet
|
|
322
|
+
const isMine = keyManager.isMineByKeys(blindingKey, spendingKey, viewTag);
|
|
323
|
+
|
|
324
|
+
// Calculate view tag for output detection
|
|
325
|
+
const viewTag = keyManager.calculateViewTag(blindingKey);
|
|
326
|
+
|
|
327
|
+
// Calculate hash ID for sub-address lookup
|
|
328
|
+
const hashId = keyManager.calculateHashId(blindingKey, spendingKey);
|
|
329
|
+
|
|
330
|
+
// Calculate nonce for amount recovery
|
|
331
|
+
const nonce = keyManager.calculateNonce(blindingKey);
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
### WalletDB
|
|
337
|
+
|
|
338
|
+
Manages wallet database persistence.
|
|
339
|
+
|
|
340
|
+
#### Wallet Operations
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// Create new wallet
|
|
344
|
+
const keyManager = await walletDB.createWallet(creationHeight);
|
|
345
|
+
|
|
346
|
+
// Load existing wallet
|
|
347
|
+
const keyManager = await walletDB.loadWallet();
|
|
348
|
+
|
|
349
|
+
// Restore wallet from seed
|
|
350
|
+
const keyManager = await walletDB.restoreWallet(seedHex, creationHeight);
|
|
351
|
+
|
|
352
|
+
// Save wallet state
|
|
353
|
+
await walletDB.saveWallet(keyManager);
|
|
354
|
+
|
|
355
|
+
// Close database
|
|
356
|
+
await walletDB.close();
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
#### Metadata
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
// Get wallet metadata
|
|
363
|
+
const metadata = await walletDB.getWalletMetadata();
|
|
364
|
+
// { creationHeight, creationTime, restoredFromSeed, version }
|
|
365
|
+
|
|
366
|
+
// Get/set creation height
|
|
367
|
+
const height = await walletDB.getCreationHeight();
|
|
368
|
+
await walletDB.setCreationHeight(height);
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
#### Balance Queries
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
// Get balance
|
|
375
|
+
const balance = await walletDB.getBalance();
|
|
376
|
+
|
|
377
|
+
// Get unspent outputs
|
|
378
|
+
const utxos = await walletDB.getUnspentOutputs();
|
|
379
|
+
|
|
380
|
+
// Get all outputs
|
|
381
|
+
const outputs = await walletDB.getAllOutputs();
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
### SyncProvider Interface
|
|
387
|
+
|
|
388
|
+
Abstract interface for sync backends. Allows switching between Electrum and P2P.
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
interface SyncProvider {
|
|
392
|
+
type: 'electrum' | 'p2p' | 'custom';
|
|
393
|
+
|
|
394
|
+
connect(): Promise<void>;
|
|
395
|
+
disconnect(): void;
|
|
396
|
+
isConnected(): boolean;
|
|
397
|
+
|
|
398
|
+
getChainTipHeight(): Promise<number>;
|
|
399
|
+
getBlockHeader(height: number): Promise<string>;
|
|
400
|
+
getBlockHeaders(startHeight: number, count: number): Promise<HeadersResult>;
|
|
401
|
+
getBlockTransactionKeysRange(startHeight: number): Promise<TransactionKeysRangeResult>;
|
|
402
|
+
getBlockTransactionKeys(height: number): Promise<TransactionKeys[]>;
|
|
403
|
+
getTransactionOutput(outputHash: string): Promise<string>;
|
|
404
|
+
broadcastTransaction(rawTx: string): Promise<string>;
|
|
405
|
+
getRawTransaction(txHash: string, verbose?: boolean): Promise<string | any>;
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
### ElectrumSyncProvider
|
|
412
|
+
|
|
413
|
+
Electrum protocol implementation of SyncProvider.
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
import { ElectrumSyncProvider } from 'navio-sdk';
|
|
417
|
+
|
|
418
|
+
const provider = new ElectrumSyncProvider({
|
|
419
|
+
host: 'localhost',
|
|
420
|
+
port: 50005,
|
|
421
|
+
ssl: false,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
await provider.connect();
|
|
425
|
+
const height = await provider.getChainTipHeight();
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
### P2PSyncProvider
|
|
431
|
+
|
|
432
|
+
Direct P2P node connection implementation of SyncProvider.
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
import { P2PSyncProvider } from 'navio-sdk';
|
|
436
|
+
|
|
437
|
+
const provider = new P2PSyncProvider({
|
|
438
|
+
host: 'localhost',
|
|
439
|
+
port: 33670,
|
|
440
|
+
network: 'testnet',
|
|
441
|
+
debug: true,
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
await provider.connect();
|
|
445
|
+
const height = await provider.getChainTipHeight();
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## Examples
|
|
451
|
+
|
|
452
|
+
### Create New Wallet
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
import { NavioClient } from 'navio-sdk';
|
|
456
|
+
|
|
457
|
+
const client = new NavioClient({
|
|
458
|
+
walletDbPath: './new-wallet.db',
|
|
459
|
+
electrum: { host: 'localhost', port: 50005 },
|
|
460
|
+
createWalletIfNotExists: true,
|
|
461
|
+
network: 'testnet',
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
await client.initialize();
|
|
465
|
+
|
|
466
|
+
// Get and save the seed for backup
|
|
467
|
+
const keyManager = client.getKeyManager();
|
|
468
|
+
const seed = keyManager.getMasterSeedKey();
|
|
469
|
+
console.log('SAVE THIS SEED:', seed.serialize());
|
|
470
|
+
|
|
471
|
+
// Get receiving address
|
|
472
|
+
const { DoublePublicKey, Address, AddressEncoding } = require('navio-blsct');
|
|
473
|
+
const subAddress = keyManager.getSubAddress({ account: 0, address: 0 });
|
|
474
|
+
const dpk = DoublePublicKey.deserialize(subAddress.serialize());
|
|
475
|
+
const address = Address.encode(dpk, AddressEncoding.Bech32M);
|
|
476
|
+
console.log('Address:', address);
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### Restore Wallet from Seed
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
const client = new NavioClient({
|
|
483
|
+
walletDbPath: './restored-wallet.db',
|
|
484
|
+
electrum: { host: 'localhost', port: 50005 },
|
|
485
|
+
restoreFromSeed: 'your-seed-hex-string',
|
|
486
|
+
restoreFromHeight: 50000, // Block height when wallet was created
|
|
487
|
+
network: 'testnet',
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
await client.initialize();
|
|
491
|
+
|
|
492
|
+
// Full sync from restoration height
|
|
493
|
+
await client.sync({
|
|
494
|
+
onProgress: (height, tip) => {
|
|
495
|
+
console.log(`Syncing: ${height}/${tip}`);
|
|
496
|
+
},
|
|
497
|
+
});
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Using P2P Backend
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
const client = new NavioClient({
|
|
504
|
+
walletDbPath: './p2p-wallet.db',
|
|
505
|
+
backend: 'p2p',
|
|
506
|
+
p2p: {
|
|
507
|
+
host: 'localhost',
|
|
508
|
+
port: 33670,
|
|
509
|
+
network: 'testnet',
|
|
510
|
+
debug: false,
|
|
511
|
+
},
|
|
512
|
+
network: 'testnet',
|
|
513
|
+
createWalletIfNotExists: true,
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
await client.initialize();
|
|
517
|
+
await client.sync();
|
|
518
|
+
|
|
519
|
+
const balance = await client.getBalanceNav();
|
|
520
|
+
console.log(`Balance: ${balance} NAV`);
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Sync with Progress
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
const startTime = Date.now();
|
|
527
|
+
|
|
528
|
+
await client.sync({
|
|
529
|
+
onProgress: (currentHeight, chainTip, blocksProcessed, txKeysProcessed, isReorg) => {
|
|
530
|
+
const progress = ((currentHeight / chainTip) * 100).toFixed(1);
|
|
531
|
+
const elapsed = (Date.now() - startTime) / 1000;
|
|
532
|
+
const rate = blocksProcessed / elapsed;
|
|
533
|
+
|
|
534
|
+
console.log(
|
|
535
|
+
`Progress: ${progress}% | ${blocksProcessed} blocks | ` +
|
|
536
|
+
`${txKeysProcessed} TX keys | ${rate.toFixed(1)} blocks/s`
|
|
537
|
+
);
|
|
538
|
+
},
|
|
539
|
+
saveInterval: 100, // Save every 100 blocks
|
|
540
|
+
});
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Background Sync (Stay Synced)
|
|
544
|
+
|
|
545
|
+
Keep the wallet synchronized automatically:
|
|
546
|
+
|
|
547
|
+
```typescript
|
|
548
|
+
import { NavioClient } from 'navio-sdk';
|
|
549
|
+
|
|
550
|
+
const client = new NavioClient({
|
|
551
|
+
walletDbPath: './wallet.db',
|
|
552
|
+
electrum: { host: 'localhost', port: 50005 },
|
|
553
|
+
createWalletIfNotExists: true,
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
await client.initialize();
|
|
557
|
+
|
|
558
|
+
// Start background sync - polls every 10 seconds
|
|
559
|
+
await client.startBackgroundSync({
|
|
560
|
+
pollInterval: 10000,
|
|
561
|
+
|
|
562
|
+
onNewBlock: (height, hash) => {
|
|
563
|
+
console.log(`New block ${height}: ${hash.substring(0, 16)}...`);
|
|
564
|
+
},
|
|
565
|
+
|
|
566
|
+
onBalanceChange: (newBalance, oldBalance) => {
|
|
567
|
+
const diff = Number(newBalance - oldBalance) / 1e8;
|
|
568
|
+
console.log(`Balance changed: ${diff > 0 ? '+' : ''}${diff.toFixed(8)} NAV`);
|
|
569
|
+
console.log(`New balance: ${Number(newBalance) / 1e8} NAV`);
|
|
570
|
+
},
|
|
571
|
+
|
|
572
|
+
onError: (error) => {
|
|
573
|
+
console.error('Sync error:', error.message);
|
|
574
|
+
},
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
console.log('Wallet running. Press Ctrl+C to stop.');
|
|
578
|
+
|
|
579
|
+
// Handle graceful shutdown
|
|
580
|
+
process.on('SIGINT', async () => {
|
|
581
|
+
console.log('\nShutting down...');
|
|
582
|
+
client.stopBackgroundSync();
|
|
583
|
+
await client.disconnect();
|
|
584
|
+
process.exit(0);
|
|
585
|
+
});
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### Query Wallet Outputs
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
// Get balance
|
|
592
|
+
const balanceNav = await client.getBalanceNav();
|
|
593
|
+
console.log(`Balance: ${balanceNav.toFixed(8)} NAV`);
|
|
594
|
+
|
|
595
|
+
// Get unspent outputs
|
|
596
|
+
const utxos = await client.getUnspentOutputs();
|
|
597
|
+
console.log(`\nUnspent Outputs (${utxos.length}):`);
|
|
598
|
+
|
|
599
|
+
for (const utxo of utxos) {
|
|
600
|
+
const amount = Number(utxo.amount) / 1e8;
|
|
601
|
+
console.log(` ${utxo.outputHash.substring(0, 16)}...`);
|
|
602
|
+
console.log(` Amount: ${amount.toFixed(8)} NAV`);
|
|
603
|
+
console.log(` Block: ${utxo.blockHeight}`);
|
|
604
|
+
if (utxo.memo) {
|
|
605
|
+
console.log(` Memo: ${utxo.memo}`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
## Database Schema
|
|
613
|
+
|
|
614
|
+
The wallet database includes the following tables:
|
|
615
|
+
|
|
616
|
+
| Table | Description |
|
|
617
|
+
|-------|-------------|
|
|
618
|
+
| `keys` | Key pairs for transactions |
|
|
619
|
+
| `out_keys` | Output-specific keys |
|
|
620
|
+
| `view_key` | View key for output detection |
|
|
621
|
+
| `spend_key` | Spending public key |
|
|
622
|
+
| `hd_chain` | HD chain information |
|
|
623
|
+
| `sub_addresses` | Sub-address mappings |
|
|
624
|
+
| `wallet_outputs` | Wallet UTXOs with amounts |
|
|
625
|
+
| `wallet_metadata` | Wallet creation info |
|
|
626
|
+
| `tx_keys` | Transaction keys (optional) |
|
|
627
|
+
| `block_hashes` | Block hashes for reorg detection |
|
|
628
|
+
| `sync_state` | Synchronization state |
|
|
629
|
+
|
|
630
|
+
### wallet_outputs Schema
|
|
631
|
+
|
|
632
|
+
```sql
|
|
633
|
+
CREATE TABLE wallet_outputs (
|
|
634
|
+
output_hash TEXT PRIMARY KEY,
|
|
635
|
+
tx_hash TEXT NOT NULL,
|
|
636
|
+
output_index INTEGER NOT NULL,
|
|
637
|
+
block_height INTEGER NOT NULL,
|
|
638
|
+
output_data TEXT NOT NULL,
|
|
639
|
+
amount INTEGER NOT NULL DEFAULT 0,
|
|
640
|
+
memo TEXT,
|
|
641
|
+
token_id TEXT,
|
|
642
|
+
blinding_key TEXT,
|
|
643
|
+
spending_key TEXT,
|
|
644
|
+
is_spent INTEGER NOT NULL DEFAULT 0,
|
|
645
|
+
spent_tx_hash TEXT,
|
|
646
|
+
spent_block_height INTEGER,
|
|
647
|
+
created_at INTEGER NOT NULL
|
|
648
|
+
);
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Optimization
|
|
654
|
+
|
|
655
|
+
The SDK includes several optimization options:
|
|
656
|
+
|
|
657
|
+
| Option | Default | Description |
|
|
658
|
+
|--------|---------|-------------|
|
|
659
|
+
| `keepTxKeys` | `false` | Don't store TX keys after processing (saves space) |
|
|
660
|
+
| `blockHashRetention` | `10000` | Only keep last 10k block hashes (~2.4 MB savings) |
|
|
661
|
+
| `saveInterval` | `100` | Save database every 100 blocks |
|
|
662
|
+
| `creationHeight` | `chainTip - 100` | Skip blocks before wallet creation |
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
## Network Configuration
|
|
667
|
+
|
|
668
|
+
The SDK uses `navio-blsct` for BLS CT operations. Network configuration is automatic based on the `network` option:
|
|
669
|
+
|
|
670
|
+
```typescript
|
|
671
|
+
import { setChain, BlsctChain, getChain } from 'navio-sdk';
|
|
672
|
+
|
|
673
|
+
// Manual configuration (usually automatic)
|
|
674
|
+
setChain(BlsctChain.Testnet);
|
|
675
|
+
console.log('Current chain:', getChain());
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
---
|
|
679
|
+
|
|
680
|
+
## Development
|
|
681
|
+
|
|
682
|
+
```bash
|
|
683
|
+
# Install dependencies
|
|
684
|
+
npm install
|
|
685
|
+
|
|
686
|
+
# Build
|
|
687
|
+
npm run build
|
|
688
|
+
|
|
689
|
+
# Run tests
|
|
690
|
+
npm run test:keymanager # KeyManager tests
|
|
691
|
+
npm run test:walletdb # WalletDB tests
|
|
692
|
+
npm run test:electrum # Electrum client tests
|
|
693
|
+
npm run test:client # Full client tests (Electrum)
|
|
694
|
+
npm run test:p2p # P2P protocol tests
|
|
695
|
+
npm run test:client:p2p # Full client tests (P2P)
|
|
696
|
+
|
|
697
|
+
# Generate documentation
|
|
698
|
+
npm run docs # HTML docs in ./docs
|
|
699
|
+
npm run docs:md # Markdown docs in ./docs/api
|
|
700
|
+
|
|
701
|
+
# Type checking
|
|
702
|
+
npm run typecheck
|
|
703
|
+
|
|
704
|
+
# Linting
|
|
705
|
+
npm run lint
|
|
706
|
+
npm run lint:fix
|
|
707
|
+
|
|
708
|
+
# Analyze database size
|
|
709
|
+
npm run analyze:db
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
## Known Limitations
|
|
715
|
+
|
|
716
|
+
1. **Amount Recovery**: The `navio-blsct` library v1.0.20 has a bug in `RangeProof.recoverAmounts()`. Outputs are detected and stored but amounts show as 0 until the library is updated.
|
|
717
|
+
|
|
718
|
+
2. **Token Support**: Token transfers are tracked but not fully implemented for spending.
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
## API Documentation
|
|
723
|
+
|
|
724
|
+
Full API documentation is auto-generated using TypeDoc:
|
|
725
|
+
|
|
726
|
+
```bash
|
|
727
|
+
npm run docs
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
View the generated documentation in the `./docs` directory.
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
## Examples
|
|
735
|
+
|
|
736
|
+
### Web Wallet
|
|
737
|
+
|
|
738
|
+
A basic browser-based wallet example is available in `examples/web-wallet/`:
|
|
739
|
+
|
|
740
|
+
```bash
|
|
741
|
+
cd examples/web-wallet
|
|
742
|
+
npm install
|
|
743
|
+
npm run dev
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
Features:
|
|
747
|
+
- Create/restore HD wallet
|
|
748
|
+
- Connect to Electrum server
|
|
749
|
+
- Background synchronization
|
|
750
|
+
- Balance and UTXO display
|
|
751
|
+
|
|
752
|
+
See [examples/web-wallet/README.md](examples/web-wallet/README.md) for details.
|
|
753
|
+
|
|
754
|
+
---
|
|
755
|
+
|
|
756
|
+
## License
|
|
757
|
+
|
|
758
|
+
MIT
|