@yellow-org/sdk 1.0.1-alpha.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.
Files changed (72) hide show
  1. package/README.md +999 -0
  2. package/dist/abis/generated.d.ts +4300 -0
  3. package/dist/abis/generated.js +1 -0
  4. package/dist/app/index.d.ts +2 -0
  5. package/dist/app/index.js +2 -0
  6. package/dist/app/packing.d.ts +7 -0
  7. package/dist/app/packing.js +111 -0
  8. package/dist/app/types.d.ts +91 -0
  9. package/dist/app/types.js +42 -0
  10. package/dist/asset_store.d.ts +13 -0
  11. package/dist/asset_store.js +121 -0
  12. package/dist/blockchain/evm/channel_hub_abi.d.ts +4284 -0
  13. package/dist/blockchain/evm/channel_hub_abi.js +5475 -0
  14. package/dist/blockchain/evm/client.d.ts +46 -0
  15. package/dist/blockchain/evm/client.js +428 -0
  16. package/dist/blockchain/evm/erc20.d.ts +13 -0
  17. package/dist/blockchain/evm/erc20.js +54 -0
  18. package/dist/blockchain/evm/erc20_abi.d.ts +144 -0
  19. package/dist/blockchain/evm/erc20_abi.js +96 -0
  20. package/dist/blockchain/evm/index.d.ts +6 -0
  21. package/dist/blockchain/evm/index.js +6 -0
  22. package/dist/blockchain/evm/interface.d.ts +10 -0
  23. package/dist/blockchain/evm/interface.js +1 -0
  24. package/dist/blockchain/evm/types.d.ts +27 -0
  25. package/dist/blockchain/evm/types.js +1 -0
  26. package/dist/blockchain/evm/utils.d.ts +9 -0
  27. package/dist/blockchain/evm/utils.js +129 -0
  28. package/dist/blockchain/index.d.ts +1 -0
  29. package/dist/blockchain/index.js +1 -0
  30. package/dist/client.d.ts +99 -0
  31. package/dist/client.js +720 -0
  32. package/dist/config.d.ts +12 -0
  33. package/dist/config.js +28 -0
  34. package/dist/core/event.d.ts +29 -0
  35. package/dist/core/event.js +1 -0
  36. package/dist/core/index.d.ts +6 -0
  37. package/dist/core/index.js +6 -0
  38. package/dist/core/interface.d.ts +53 -0
  39. package/dist/core/interface.js +1 -0
  40. package/dist/core/state.d.ts +21 -0
  41. package/dist/core/state.js +267 -0
  42. package/dist/core/state_packer.d.ts +13 -0
  43. package/dist/core/state_packer.js +98 -0
  44. package/dist/core/types.d.ts +203 -0
  45. package/dist/core/types.js +220 -0
  46. package/dist/core/utils.d.ts +16 -0
  47. package/dist/core/utils.js +181 -0
  48. package/dist/index.d.ts +9 -0
  49. package/dist/index.js +9 -0
  50. package/dist/rpc/api.d.ts +181 -0
  51. package/dist/rpc/api.js +1 -0
  52. package/dist/rpc/client.d.ts +36 -0
  53. package/dist/rpc/client.js +102 -0
  54. package/dist/rpc/dialer.d.ts +30 -0
  55. package/dist/rpc/dialer.js +146 -0
  56. package/dist/rpc/error.d.ts +18 -0
  57. package/dist/rpc/error.js +27 -0
  58. package/dist/rpc/index.d.ts +7 -0
  59. package/dist/rpc/index.js +7 -0
  60. package/dist/rpc/message.d.ts +25 -0
  61. package/dist/rpc/message.js +102 -0
  62. package/dist/rpc/methods.d.ts +30 -0
  63. package/dist/rpc/methods.js +27 -0
  64. package/dist/rpc/types.d.ts +101 -0
  65. package/dist/rpc/types.js +1 -0
  66. package/dist/signers.d.ts +48 -0
  67. package/dist/signers.js +96 -0
  68. package/dist/utils/sign.d.ts +2 -0
  69. package/dist/utils/sign.js +8 -0
  70. package/dist/utils.d.ts +42 -0
  71. package/dist/utils.js +226 -0
  72. package/package.json +89 -0
package/README.md ADDED
@@ -0,0 +1,999 @@
1
+ # Clearnode TypeScript SDK
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@erc7824/nitrolite.svg)](https://www.npmjs.com/package/@erc7824/nitrolite)
4
+ [![License](https://img.shields.io/npm/l/@erc7824/nitrolite.svg)](https://github.com/erc7824/nitrolite/blob/main/LICENSE)
5
+ [![Documentation](https://img.shields.io/badge/docs-website-blue)](https://erc7824.org/quick_start)
6
+
7
+ TypeScript SDK for Clearnode payment channels providing both high-level and low-level operations in a unified client:
8
+ - **State Operations**: `deposit()`, `withdraw()`, `transfer()`, `closeHomeChannel()`, `acknowledge()` - build and co-sign states off-chain
9
+ - **Blockchain Settlement**: `checkpoint()` - the single entry point for all on-chain transactions
10
+ - **Low-Level Operations**: Direct RPC access for custom flows and advanced use cases
11
+ - **Full Feature Parity**: 100% compatibility with Go SDK functionality
12
+
13
+ ## Method Cheat Sheet
14
+
15
+ ### State Operations (Off-Chain)
16
+ ```typescript
17
+ client.deposit(blockchainId, asset, amount) // Prepare deposit state
18
+ client.withdraw(blockchainId, asset, amount) // Prepare withdrawal state
19
+ client.transfer(recipientWallet, asset, amount) // Prepare transfer state
20
+ client.closeHomeChannel(asset) // Prepare finalize state
21
+ client.acknowledge(asset) // Acknowledge received state
22
+ ```
23
+
24
+ ### Blockchain Settlement
25
+ ```typescript
26
+ client.checkpoint(asset) // Settle latest state on-chain
27
+ client.challenge(state) // Submit on-chain challenge
28
+ client.approveToken(chainId, asset, amount) // Approve token spending
29
+ client.checkTokenAllowance(chainId, token, owner) // Check token allowance
30
+ ```
31
+
32
+ ### Node Information
33
+ ```typescript
34
+ client.ping() // Health check
35
+ client.getConfig() // Node configuration
36
+ client.getBlockchains() // Supported blockchains
37
+ client.getAssets(blockchainId?) // Supported assets
38
+ ```
39
+
40
+ ### User Queries
41
+ ```typescript
42
+ client.getBalances(wallet) // User balances
43
+ client.getTransactions(wallet, opts) // Transaction history
44
+ ```
45
+
46
+ ### Channel Queries
47
+ ```typescript
48
+ client.getChannels(wallet, options?) // List all channels
49
+ client.getHomeChannel(wallet, asset) // Home channel info
50
+ client.getEscrowChannel(escrowChannelId) // Escrow channel info
51
+ client.getLatestState(wallet, asset, onlySigned) // Latest state
52
+ ```
53
+
54
+ ### App Sessions
55
+ ```typescript
56
+ client.getAppSessions(opts) // List sessions
57
+ client.getAppDefinition(appSessionId) // Session definition
58
+ client.createAppSession(definition, sessionData, sigs) // Create session
59
+ client.submitAppSessionDeposit(update, sigs, asset, amount) // Deposit to session
60
+ client.submitAppState(update, sigs) // Update session
61
+ client.rebalanceAppSessions(signedUpdates) // Atomic rebalance
62
+ ```
63
+
64
+ ### App Session Keys
65
+ ```typescript
66
+ client.signSessionKeyState(state) // Sign app session key state
67
+ client.submitSessionKeyState(state) // Register/update app session key
68
+ client.getLastKeyStates(userAddress, sessionKey?) // Get active app session key states
69
+ ```
70
+
71
+ ### Channel Session Keys
72
+ ```typescript
73
+ client.signChannelSessionKeyState(state) // Sign channel session key state
74
+ client.submitChannelSessionKeyState(state) // Register/update channel session key
75
+ client.getLastChannelKeyStates(userAddress, sessionKey?) // Get active channel session key states
76
+ ```
77
+
78
+ ### Shared Utilities
79
+ ```typescript
80
+ client.close() // Close connection
81
+ client.waitForClose() // Connection monitor promise
82
+ client.signState(state) // Sign a state (advanced)
83
+ client.getUserAddress() // Get signer's address
84
+ client.setHomeBlockchain(asset, chainId) // Set default blockchain for asset
85
+ ```
86
+
87
+ ## Installation
88
+
89
+ ```bash
90
+ npm install @erc7824/nitrolite
91
+ # or
92
+ yarn add @erc7824/nitrolite
93
+ # or
94
+ pnpm add @erc7824/nitrolite
95
+ ```
96
+
97
+ ## Quick Start
98
+
99
+ ### Unified Client (High-Level + Low-Level)
100
+
101
+ ```typescript
102
+ import { Client, createSigners, withBlockchainRPC } from '@erc7824/nitrolite';
103
+ import Decimal from 'decimal.js';
104
+
105
+ async function main() {
106
+ // Create signers from private key
107
+ const { stateSigner, txSigner } = createSigners(
108
+ process.env.PRIVATE_KEY as `0x${string}`
109
+ );
110
+
111
+ // Create unified client
112
+ const client = await Client.create(
113
+ 'wss://clearnode.example.com/ws',
114
+ stateSigner,
115
+ txSigner,
116
+ withBlockchainRPC(80002n, 'https://polygon-amoy.alchemy.com/v2/KEY')
117
+ );
118
+
119
+ try {
120
+ // Step 1: Build and co-sign states off-chain
121
+ const state = await client.deposit(80002n, 'usdc', new Decimal(100));
122
+ console.log('Deposit state version:', state.version);
123
+
124
+ // Step 2: Settle on-chain via checkpoint
125
+ const txHash = await client.checkpoint('usdc');
126
+ console.log('On-chain tx:', txHash);
127
+
128
+ // Transfer (off-chain only, no checkpoint needed for existing channels)
129
+ const transferState = await client.transfer('0xRecipient...', 'usdc', new Decimal(50));
130
+
131
+ // Low-level operations - same client
132
+ const config = await client.getConfig();
133
+ const balances = await client.getBalances(client.getUserAddress());
134
+ } finally {
135
+ await client.close();
136
+ }
137
+ }
138
+
139
+ main().catch(console.error);
140
+ ```
141
+
142
+ ## Architecture
143
+
144
+ ```
145
+ sdk/ts/src/
146
+ ├── client.ts # Core client, constructors, high-level operations
147
+ ├── signers.ts # EthereumMsgSigner and EthereumRawSigner
148
+ ├── config.ts # Configuration options
149
+ ├── asset_store.ts # Asset metadata caching
150
+ ├── utils.ts # Type transformations
151
+ ├── core/ # State management, transitions, types
152
+ ├── rpc/ # WebSocket RPC client
153
+ ├── blockchain/ # EVM blockchain interactions
154
+ └── app/ # App session types and logic
155
+ ```
156
+
157
+ ## Client API
158
+
159
+ ### Creating a Client
160
+
161
+ ```typescript
162
+ import { Client, createSigners, withBlockchainRPC } from '@erc7824/nitrolite';
163
+
164
+ // Step 1: Create signers from private key
165
+ const { stateSigner, txSigner } = createSigners('0x1234...');
166
+
167
+ // Step 2: Create unified client
168
+ const client = await Client.create(
169
+ wsURL,
170
+ stateSigner, // For signing channel states
171
+ txSigner, // For signing blockchain transactions
172
+ withBlockchainRPC(chainId, rpcURL), // Required for Checkpoint
173
+ withHandshakeTimeout(10000), // Optional: connection timeout
174
+ withPingInterval(5000) // Optional: keepalive interval
175
+ );
176
+
177
+ // Step 3: (Optional) Set home blockchain for assets
178
+ // Required for Transfer operations that may trigger channel creation
179
+ await client.setHomeBlockchain('usdc', 80002n);
180
+ ```
181
+
182
+ ### Signer Implementations
183
+
184
+ The SDK provides two signer types matching the Go SDK patterns:
185
+
186
+ #### EthereumMsgSigner (for channel states)
187
+
188
+ Signs channel state updates with EIP-191 "Ethereum Signed Message" prefix.
189
+
190
+ ```typescript
191
+ import { EthereumMsgSigner } from '@erc7824/nitrolite';
192
+ import { privateKeyToAccount } from 'viem/accounts';
193
+
194
+ // From private key
195
+ const signer1 = new EthereumMsgSigner('0x...');
196
+
197
+ // From viem account
198
+ const account = privateKeyToAccount('0x...');
199
+ const signer2 = new EthereumMsgSigner(account);
200
+ ```
201
+
202
+ **When to use**: All off-chain operations (state signatures, transfers)
203
+
204
+ #### EthereumRawSigner (for blockchain transactions)
205
+
206
+ Signs raw hashes directly without prefix for on-chain operations.
207
+
208
+ ```typescript
209
+ import { EthereumRawSigner } from '@erc7824/nitrolite';
210
+
211
+ const signer = new EthereumRawSigner('0x...');
212
+ ```
213
+
214
+ **When to use**: On-chain operations (deposits, withdrawals, channel creation)
215
+
216
+ #### Helper: createSigners()
217
+
218
+ ```typescript
219
+ import { createSigners } from '@erc7824/nitrolite';
220
+
221
+ // Creates both signers at once
222
+ const { stateSigner, txSigner } = createSigners('0x...');
223
+ const client = await Client.create(wsURL, stateSigner, txSigner);
224
+ ```
225
+
226
+ ### Configuring Home Blockchain
227
+
228
+ #### `setHomeBlockchain(asset, blockchainId)`
229
+
230
+ Sets the default blockchain network for a specific asset. Required for `transfer()` operations that may trigger channel creation.
231
+
232
+ ```typescript
233
+ await client.setHomeBlockchain('usdc', 80002n);
234
+ ```
235
+
236
+ **Important Notes:**
237
+ - This mapping is immutable once set for the client instance
238
+ - The asset must be supported on the specified blockchain
239
+ - Required before calling `transfer()` on a new channel
240
+
241
+ ### State Operations
242
+
243
+ All state operations build and co-sign a state off-chain. They return `Promise<core.State>`. Use `checkpoint()` to settle the state on-chain.
244
+
245
+ #### `deposit(blockchainId, asset, amount): Promise<core.State>`
246
+
247
+ Prepares a deposit state. Creates a new channel if none exists, otherwise advances the existing state.
248
+
249
+ ```typescript
250
+ const state = await client.deposit(80002n, 'usdc', new Decimal(100));
251
+ const txHash = await client.checkpoint('usdc'); // settle on-chain
252
+ ```
253
+
254
+ **Requirements:**
255
+ - Sufficient token balance (checked on-chain during checkpoint)
256
+
257
+ **Scenarios:**
258
+ 1. **No channel exists**: Creates new channel with initial deposit
259
+ 2. **Channel exists**: Advances the existing state with a deposit transition
260
+
261
+ #### `withdraw(blockchainId, asset, amount): Promise<core.State>`
262
+
263
+ Prepares a withdrawal state to remove funds from the channel.
264
+
265
+ ```typescript
266
+ const state = await client.withdraw(80002n, 'usdc', new Decimal(25));
267
+ const txHash = await client.checkpoint('usdc'); // settle on-chain
268
+ ```
269
+
270
+ **Requirements:**
271
+ - Existing channel with sufficient balance
272
+
273
+ #### `transfer(recipientWallet, asset, amount): Promise<core.State>`
274
+
275
+ Prepares an off-chain transfer to another wallet. For existing channels, no checkpoint is needed.
276
+
277
+ ```typescript
278
+ const state = await client.transfer(
279
+ '0xRecipient...', // Recipient address
280
+ 'usdc', // Asset symbol
281
+ new Decimal(50) // Amount
282
+ );
283
+ ```
284
+
285
+ **Requirements:**
286
+ - Existing channel with sufficient balance OR
287
+ - Home blockchain configured via `setHomeBlockchain()` (for new channels)
288
+
289
+ #### `closeHomeChannel(asset): Promise<core.State>`
290
+
291
+ Prepares a finalize state to close the user's channel for a specific asset.
292
+
293
+ ```typescript
294
+ const state = await client.closeHomeChannel('usdc');
295
+ const txHash = await client.checkpoint('usdc'); // close on-chain
296
+ ```
297
+
298
+ **Requirements:**
299
+ - Existing channel (user must have deposited first)
300
+
301
+ #### `acknowledge(asset): Promise<core.State>`
302
+
303
+ Acknowledges a received state (e.g., after receiving a transfer).
304
+
305
+ ```typescript
306
+ const state = await client.acknowledge('usdc');
307
+ ```
308
+
309
+ **Requirements:**
310
+ - Home blockchain configured via `setHomeBlockchain()` when no channel exists
311
+
312
+ ### Blockchain Settlement
313
+
314
+ #### `checkpoint(asset): Promise<string>`
315
+
316
+ Settles the latest co-signed state on-chain. This is the single entry point for all blockchain transactions. Based on the transition type and on-chain channel status, it calls the appropriate blockchain method:
317
+
318
+ - **Channel not on-chain** (status Void): Creates the channel
319
+ - **Deposit/Withdrawal on existing channel**: Checkpoints the state
320
+ - **Finalize**: Closes the channel
321
+
322
+ ```typescript
323
+ const txHash = await client.checkpoint('usdc');
324
+ ```
325
+
326
+ **Requirements:**
327
+ - Blockchain RPC configured via `withBlockchainRPC()`
328
+ - A co-signed state must exist (call `deposit()`, `withdraw()`, etc. first)
329
+ - Sufficient gas for the blockchain transaction
330
+
331
+ #### `challenge(state): Promise<string>`
332
+
333
+ Submits an on-chain challenge for a channel using a co-signed state. Initiates a dispute period on-chain.
334
+
335
+ ```typescript
336
+ const state = await client.getLatestState(wallet, 'usdc', true);
337
+ const txHash = await client.challenge(state);
338
+ ```
339
+
340
+ **Requirements:**
341
+ - State must have both user and node signatures
342
+
343
+ #### `approveToken(chainId, asset, amount): Promise<string>`
344
+
345
+ Approves the ChannelHub contract to spend tokens on behalf of the user. Required before depositing ERC-20 tokens.
346
+
347
+ ```typescript
348
+ const txHash = await client.approveToken(80002n, 'usdc', new Decimal(1000));
349
+ ```
350
+
351
+ #### `checkTokenAllowance(chainId, tokenAddress, owner): Promise<bigint>`
352
+
353
+ Checks the current token allowance for the ChannelHub contract.
354
+
355
+ ```typescript
356
+ const allowance = await client.checkTokenAllowance(80002n, '0xToken...', '0xOwner...');
357
+ ```
358
+
359
+ ## Low-Level API
360
+
361
+ All low-level RPC methods are available on the same Client instance.
362
+
363
+ ### Node Information
364
+
365
+ ```typescript
366
+ await client.ping();
367
+ const config = await client.getConfig();
368
+ const blockchains = await client.getBlockchains();
369
+ const assets = await client.getAssets(); // or client.getAssets(blockchainId)
370
+ ```
371
+
372
+ ### User Data
373
+
374
+ ```typescript
375
+ const balances = await client.getBalances(wallet);
376
+ const { transactions, metadata } = await client.getTransactions(wallet, {
377
+ page: 1,
378
+ pageSize: 50,
379
+ });
380
+ ```
381
+
382
+ ### Channel Queries
383
+
384
+ ```typescript
385
+ const { channels, metadata } = await client.getChannels(wallet);
386
+ const channel = await client.getHomeChannel(wallet, asset);
387
+ const escrow = await client.getEscrowChannel(escrowChannelId);
388
+ const state = await client.getLatestState(wallet, asset, onlySigned);
389
+ ```
390
+
391
+ **Note:** State submission and channel creation are handled internally by state operations (`deposit()`, `withdraw()`, `transfer()`). On-chain settlement is handled by `checkpoint()`.
392
+
393
+ ### App Sessions (Low-Level)
394
+
395
+ ```typescript
396
+ // Query sessions
397
+ const { sessions, metadata } = await client.getAppSessions(opts);
398
+ const definition = await client.getAppDefinition(appSessionId);
399
+
400
+ // Create and manage sessions
401
+ const { appSessionId, version, status } = await client.createAppSession(
402
+ definition,
403
+ sessionData,
404
+ signatures
405
+ );
406
+
407
+ const nodeSig = await client.submitAppSessionDeposit(
408
+ appUpdate,
409
+ quorumSigs,
410
+ asset,
411
+ depositAmount
412
+ );
413
+
414
+ await client.submitAppState(appUpdate, quorumSigs);
415
+
416
+ const batchId = await client.rebalanceAppSessions(signedUpdates);
417
+ ```
418
+
419
+ ### App Session Keys
420
+
421
+ ```typescript
422
+ // Sign and submit an app session key state
423
+ const sig = await client.signSessionKeyState({
424
+ user_address: '0x1234...',
425
+ session_key: '0xabcd...',
426
+ version: '1',
427
+ application_ids: ['app1'],
428
+ app_session_ids: [],
429
+ expires_at: String(Math.floor(Date.now() / 1000) + 86400),
430
+ user_sig: '0x',
431
+ });
432
+
433
+ await client.submitSessionKeyState({
434
+ user_address: '0x1234...',
435
+ session_key: '0xabcd...',
436
+ version: '1',
437
+ application_ids: ['app1'],
438
+ app_session_ids: [],
439
+ expires_at: String(Math.floor(Date.now() / 1000) + 86400),
440
+ user_sig: sig,
441
+ });
442
+
443
+ // Query active app session key states
444
+ const states = await client.getLastKeyStates('0x1234...');
445
+ const filtered = await client.getLastKeyStates('0x1234...', '0xSessionKey...');
446
+ ```
447
+
448
+ ### Channel Session Keys
449
+
450
+ ```typescript
451
+ // Sign and submit a channel session key state
452
+ const sig = await client.signChannelSessionKeyState({
453
+ user_address: '0x1234...',
454
+ session_key: '0xabcd...',
455
+ version: '1',
456
+ assets: ['usdc'],
457
+ expires_at: String(Math.floor(Date.now() / 1000) + 86400),
458
+ user_sig: '0x',
459
+ });
460
+
461
+ await client.submitChannelSessionKeyState({
462
+ user_address: '0x1234...',
463
+ session_key: '0xabcd...',
464
+ version: '1',
465
+ assets: ['usdc'],
466
+ expires_at: String(Math.floor(Date.now() / 1000) + 86400),
467
+ user_sig: sig,
468
+ });
469
+
470
+ // Query active channel session key states
471
+ const states = await client.getLastChannelKeyStates('0x1234...');
472
+ const filtered = await client.getLastChannelKeyStates('0x1234...', '0xSessionKey...');
473
+ ```
474
+
475
+ ## Key Concepts
476
+
477
+ ### State Management
478
+
479
+ Payment channels use versioned states signed by both user and node. The SDK uses a two-step pattern:
480
+
481
+ ```typescript
482
+ // Step 1: Build and co-sign state off-chain
483
+ const state = await client.deposit(...); // Returns core.State
484
+ const state = await client.withdraw(...); // Returns core.State
485
+ const state = await client.transfer(...); // Returns core.State
486
+
487
+ // Step 2: Settle on-chain (when needed)
488
+ const txHash = await client.checkpoint('usdc');
489
+ ```
490
+
491
+ **State Flow (Internal):**
492
+ 1. Get latest state with `getLatestState()`
493
+ 2. Create next state with `nextState()`
494
+ 3. Apply transition (deposit, withdraw, transfer, etc.)
495
+ 4. Sign state with `signState()`
496
+ 5. Submit to node for co-signing
497
+ 6. Return co-signed state
498
+
499
+ On-chain settlement is handled separately by `checkpoint()`.
500
+
501
+ ### Signing
502
+
503
+ States are signed using ECDSA with EIP-191/EIP-155:
504
+
505
+ ```typescript
506
+ // Create signers from private key
507
+ const { stateSigner, txSigner } = createSigners('0x...');
508
+
509
+ // Get address
510
+ const address = stateSigner.getAddress();
511
+ ```
512
+
513
+ **Signing Process:**
514
+ 1. State -> ABI Encode (via `packState`)
515
+ 2. Packed State -> Keccak256 Hash
516
+ 3. Hash -> ECDSA Sign (via signer)
517
+ 4. Result: 65-byte signature (R || S || V)
518
+
519
+ **Two Signer Types:**
520
+ - `EthereumMsgSigner`: Signs channel state updates (off-chain signatures) with EIP-191 prefix
521
+ - `EthereumRawSigner`: Signs blockchain transactions (on-chain operations) without prefix
522
+
523
+ ### Channel Lifecycle
524
+
525
+ 1. **Void**: No channel exists
526
+ 2. **Create**: Deposit creates channel on-chain
527
+ 3. **Open**: Channel active, can deposit/withdraw/transfer
528
+ 4. **Challenged**: Dispute initiated (advanced)
529
+ 5. **Closed**: Channel finalized (advanced)
530
+
531
+ ## When to Use State Operations vs Low-Level Operations
532
+
533
+ ### Use State Operations When:
534
+ - Building user-facing applications
535
+ - Need simple deposit/withdraw/transfer
536
+ - Want automatic state management with two-step pattern
537
+ - Don't need custom flows
538
+
539
+ ### Use Low-Level Operations When:
540
+ - Building infrastructure/tooling
541
+ - Implementing custom state transitions
542
+ - Need fine-grained control
543
+ - Working with app sessions directly
544
+
545
+ ## Error Handling
546
+
547
+ All errors include context:
548
+
549
+ ```typescript
550
+ try {
551
+ const state = await client.deposit(80002n, 'usdc', amount);
552
+ const txHash = await client.checkpoint('usdc');
553
+ } catch (error) {
554
+ // State error: "channel not created, deposit first"
555
+ // Checkpoint error: "failed to create channel on blockchain: insufficient balance"
556
+ console.error('Operation failed:', error);
557
+ }
558
+ ```
559
+
560
+ ### Common Errors
561
+
562
+ | Error Message | Cause | Solution |
563
+ |--------------|-------|----------|
564
+ | `"channel not created, deposit first"` | Transfer before deposit | Deposit funds first |
565
+ | `"home blockchain not set for asset"` | Missing `setHomeBlockchain()` | Call `setHomeBlockchain()` before transfer |
566
+ | `"blockchain client not configured"` | Missing `withBlockchainRPC()` | Add `withBlockchainRPC()` configuration |
567
+ | `"insufficient balance"` | Not enough funds | Deposit more funds |
568
+ | `"failed to sign state"` | Invalid private key or state | Check signer configuration |
569
+ | `"no channel exists for asset"` | Checkpoint called without a co-signed state | Call `deposit()`, `withdraw()`, etc. first |
570
+ | `"transition type ... does not require a blockchain operation"` | Checkpoint called on unsupported transition | Only checkpoint after deposit, withdraw, close, or acknowledge |
571
+
572
+ ### Custom Error Handler
573
+
574
+ ```typescript
575
+ const client = await Client.create(
576
+ wsURL,
577
+ stateSigner,
578
+ txSigner,
579
+ withErrorHandler((error) => {
580
+ console.error('[Connection Error]', error);
581
+ // Custom error handling logic
582
+ })
583
+ );
584
+ ```
585
+
586
+ ## Configuration Options
587
+
588
+ ```typescript
589
+ import {
590
+ withBlockchainRPC,
591
+ withHandshakeTimeout,
592
+ withPingInterval,
593
+ withErrorHandler
594
+ } from '@erc7824/nitrolite';
595
+
596
+ const client = await Client.create(
597
+ wsURL,
598
+ stateSigner,
599
+ txSigner,
600
+ withBlockchainRPC(chainId, rpcURL), // Configure blockchain RPC (required for Checkpoint)
601
+ withHandshakeTimeout(10000), // Connection timeout (ms, default: 5000)
602
+ withPingInterval(5000), // Keepalive interval (ms, default: 5000)
603
+ withErrorHandler(func) // Connection error handler
604
+ );
605
+ ```
606
+
607
+ ## Complete Examples
608
+
609
+ ### Example 1: Basic Deposit and Transfer
610
+
611
+ ```typescript
612
+ import { Client, createSigners, withBlockchainRPC } from '@erc7824/nitrolite';
613
+ import Decimal from 'decimal.js';
614
+
615
+ async function basicExample() {
616
+ const { stateSigner, txSigner } = createSigners(process.env.PRIVATE_KEY!);
617
+
618
+ const client = await Client.create(
619
+ 'wss://clearnode.example.com/ws',
620
+ stateSigner,
621
+ txSigner,
622
+ withBlockchainRPC(80002n, process.env.RPC_URL!)
623
+ );
624
+
625
+ try {
626
+ console.log('User:', client.getUserAddress());
627
+
628
+ // Set home blockchain
629
+ await client.setHomeBlockchain('usdc', 80002n);
630
+
631
+ // Step 1: Build and co-sign deposit state
632
+ const depositState = await client.deposit(80002n, 'usdc', new Decimal(100));
633
+ console.log('Deposit state version:', depositState.version);
634
+
635
+ // Step 2: Settle on-chain
636
+ const txHash = await client.checkpoint('usdc');
637
+ console.log('On-chain tx:', txHash);
638
+
639
+ // Check balance
640
+ const balances = await client.getBalances(client.getUserAddress());
641
+ console.log('Balances:', balances);
642
+
643
+ // Transfer 50 USDC (off-chain, no checkpoint needed)
644
+ const transferState = await client.transfer(
645
+ '0xRecipient...',
646
+ 'usdc',
647
+ new Decimal(50)
648
+ );
649
+ console.log('Transfer state version:', transferState.version);
650
+ } finally {
651
+ await client.close();
652
+ }
653
+ }
654
+
655
+ basicExample().catch(console.error);
656
+ ```
657
+
658
+ ### Example 2: Multi-Chain Operations
659
+
660
+ ```typescript
661
+ import { Client, createSigners, withBlockchainRPC } from '@erc7824/nitrolite';
662
+ import Decimal from 'decimal.js';
663
+
664
+ async function multiChainExample() {
665
+ const { stateSigner, txSigner } = createSigners(process.env.PRIVATE_KEY!);
666
+
667
+ const client = await Client.create(
668
+ 'wss://clearnode.example.com/ws',
669
+ stateSigner,
670
+ txSigner,
671
+ withBlockchainRPC(80002n, process.env.POLYGON_RPC!), // Polygon Amoy
672
+ withBlockchainRPC(11155111n, process.env.SEPOLIA_RPC!) // Sepolia
673
+ );
674
+
675
+ try {
676
+ // Set home blockchains
677
+ await client.setHomeBlockchain('usdc', 80002n);
678
+ await client.setHomeBlockchain('eth', 11155111n);
679
+
680
+ // Deposit on different chains (two-step pattern)
681
+ await client.deposit(80002n, 'usdc', new Decimal(100));
682
+ await client.checkpoint('usdc');
683
+
684
+ await client.deposit(11155111n, 'eth', new Decimal(0.1));
685
+ await client.checkpoint('eth');
686
+
687
+ // Check balances across all chains
688
+ const balances = await client.getBalances(client.getUserAddress());
689
+ balances.forEach(b => console.log(`${b.asset}: ${b.balance}`));
690
+ } finally {
691
+ await client.close();
692
+ }
693
+ }
694
+
695
+ multiChainExample().catch(console.error);
696
+ ```
697
+
698
+ ### Example 3: Transaction History with Pagination
699
+
700
+ ```typescript
701
+ import { Client, createSigners } from '@erc7824/nitrolite';
702
+
703
+ async function queryTransactions() {
704
+ const { stateSigner, txSigner } = createSigners(process.env.PRIVATE_KEY!);
705
+ const client = await Client.create(
706
+ 'wss://clearnode.example.com/ws',
707
+ stateSigner,
708
+ txSigner
709
+ );
710
+
711
+ try {
712
+ const wallet = client.getUserAddress();
713
+
714
+ // Get paginated transactions
715
+ const result = await client.getTransactions(wallet, {
716
+ page: 1,
717
+ pageSize: 10,
718
+ });
719
+
720
+ console.log(`Total: ${result.metadata.totalCount}`);
721
+ console.log(`Page ${result.metadata.page} of ${result.metadata.pageCount}`);
722
+
723
+ result.transactions.forEach((tx, i) => {
724
+ console.log(`${i + 1}. ${tx.txType}: ${tx.amount} ${tx.asset}`);
725
+ });
726
+ } finally {
727
+ await client.close();
728
+ }
729
+ }
730
+
731
+ queryTransactions().catch(console.error);
732
+ ```
733
+
734
+ ### Example 4: App Session Workflow
735
+
736
+ ```typescript
737
+ import { Client, createSigners, withBlockchainRPC } from '@erc7824/nitrolite';
738
+ import Decimal from 'decimal.js';
739
+
740
+ async function appSessionExample() {
741
+ const { stateSigner, txSigner } = createSigners(process.env.PRIVATE_KEY!);
742
+ const client = await Client.create(
743
+ 'wss://clearnode.example.com/ws',
744
+ stateSigner,
745
+ txSigner,
746
+ withBlockchainRPC(80002n, process.env.RPC_URL!)
747
+ );
748
+
749
+ try {
750
+ // Create app session
751
+ const definition = {
752
+ application: 'chess-v1',
753
+ participants: [
754
+ { walletAddress: client.getUserAddress(), signatureWeight: 1 },
755
+ { walletAddress: '0xOpponent...', signatureWeight: 1 },
756
+ ],
757
+ quorum: 2,
758
+ nonce: 1n,
759
+ };
760
+
761
+ const { appSessionId } = await client.createAppSession(
762
+ definition,
763
+ '{}',
764
+ ['sig1', 'sig2']
765
+ );
766
+ console.log('Session created:', appSessionId);
767
+
768
+ // Deposit to app session
769
+ const appUpdate = {
770
+ appSessionId,
771
+ intent: 1, // Deposit
772
+ version: 1n,
773
+ allocations: [{
774
+ participant: client.getUserAddress(),
775
+ asset: 'usdc',
776
+ amount: new Decimal(50),
777
+ }],
778
+ sessionData: '{}',
779
+ };
780
+
781
+ const nodeSig = await client.submitAppSessionDeposit(
782
+ appUpdate,
783
+ ['sig1'],
784
+ 'usdc',
785
+ new Decimal(50)
786
+ );
787
+ console.log('Deposit signature:', nodeSig);
788
+
789
+ // Query sessions
790
+ const { sessions } = await client.getAppSessions({
791
+ wallet: client.getUserAddress(),
792
+ });
793
+ console.log(`Found ${sessions.length} sessions`);
794
+ } finally {
795
+ await client.close();
796
+ }
797
+ }
798
+
799
+ appSessionExample().catch(console.error);
800
+ ```
801
+
802
+ ### Example 5: Connection Monitoring
803
+
804
+ ```typescript
805
+ import { Client, createSigners, withErrorHandler, withPingInterval } from '@erc7824/nitrolite';
806
+
807
+ async function monitorConnection() {
808
+ const { stateSigner, txSigner } = createSigners(process.env.PRIVATE_KEY!);
809
+
810
+ const client = await Client.create(
811
+ 'wss://clearnode.example.com/ws',
812
+ stateSigner,
813
+ txSigner,
814
+ withPingInterval(3000),
815
+ withErrorHandler((error) => {
816
+ console.error('Connection error:', error);
817
+ })
818
+ );
819
+
820
+ // Monitor connection
821
+ client.waitForClose().then(() => {
822
+ console.log('Connection closed, reconnecting...');
823
+ // Reconnection logic here
824
+ });
825
+
826
+ // Perform operations
827
+ const config = await client.getConfig();
828
+ console.log('Connected to:', config.nodeAddress);
829
+
830
+ // Keep alive...
831
+ await new Promise(resolve => setTimeout(resolve, 30000));
832
+ await client.close();
833
+ }
834
+
835
+ monitorConnection().catch(console.error);
836
+ ```
837
+
838
+ ## TypeScript-Specific Notes
839
+
840
+ ### Type Imports
841
+
842
+ ```typescript
843
+ import type {
844
+ State,
845
+ Channel,
846
+ Transaction,
847
+ BalanceEntry,
848
+ Asset,
849
+ Blockchain,
850
+ AppSessionInfoV1,
851
+ AppDefinitionV1,
852
+ AppSessionKeyStateV1,
853
+ ChannelSessionKeyStateV1,
854
+ PaginationMetadata,
855
+ } from '@erc7824/nitrolite';
856
+ ```
857
+
858
+ ### BigInt for Chain IDs
859
+
860
+ ```typescript
861
+ // Use 'n' suffix for bigint literals
862
+ const polygonAmoy = 80002n;
863
+ const ethereum = 1n;
864
+
865
+ await client.deposit(polygonAmoy, 'usdc', amount);
866
+ ```
867
+
868
+ ### Decimal.js for Amounts
869
+
870
+ ```typescript
871
+ import Decimal from 'decimal.js';
872
+
873
+ const amount1 = new Decimal(100);
874
+ const amount2 = new Decimal('123.456');
875
+ const amount3 = Decimal.div(1000, 3);
876
+
877
+ await client.deposit(chainId, 'usdc', amount1);
878
+ ```
879
+
880
+ ### Viem Integration
881
+
882
+ ```typescript
883
+ import { privateKeyToAccount } from 'viem/accounts';
884
+ import type { Address } from 'viem';
885
+
886
+ const account = privateKeyToAccount('0x...');
887
+ const stateSigner = new EthereumMsgSigner(account);
888
+
889
+ const wallet: Address = '0x1234...';
890
+ const balances = await client.getBalances(wallet);
891
+ ```
892
+
893
+ ### Async/Await
894
+
895
+ ```typescript
896
+ // All SDK methods are async
897
+ // State operations return core.State
898
+ const state = await client.deposit(chainId, asset, amount);
899
+ // Checkpoint returns a transaction hash
900
+ const txHash = await client.checkpoint(asset);
901
+
902
+ // Or with .then()
903
+ client.deposit(chainId, asset, amount)
904
+ .then(state => console.log('Deposit state version:', state.version))
905
+ .catch(error => console.error('Error:', error));
906
+ ```
907
+
908
+ ## Operation Internals
909
+
910
+ For understanding how operations work under the hood:
911
+
912
+ ### Deposit Flow (New Channel)
913
+ 1. Create channel definition
914
+ 2. Create void state
915
+ 3. Set home ledger (token, chain)
916
+ 4. Apply deposit transition
917
+ 5. Sign state
918
+ 6. Request channel creation from node (co-sign)
919
+ 7. Return co-signed state
920
+
921
+ ### Deposit Flow (Existing Channel)
922
+ 1. Get latest state
923
+ 2. Create next state
924
+ 3. Apply deposit transition
925
+ 4. Sign state
926
+ 5. Submit to node (co-sign)
927
+ 6. Return co-signed state
928
+
929
+ ### Withdraw Flow
930
+ 1. Get latest state
931
+ 2. Create next state
932
+ 3. Apply withdrawal transition
933
+ 4. Sign state
934
+ 5. Submit to node (co-sign)
935
+ 6. Return co-signed state
936
+
937
+ ### Transfer Flow
938
+ 1. Get latest state
939
+ 2. Create next state
940
+ 3. Apply transfer transition
941
+ 4. Sign state
942
+ 5. Submit to node (co-sign)
943
+ 6. Return co-signed state
944
+
945
+ ### CloseHomeChannel Flow
946
+ 1. Get latest state
947
+ 2. Verify channel exists
948
+ 3. Create next state
949
+ 4. Apply finalize transition
950
+ 5. Sign state
951
+ 6. Submit to node (co-sign)
952
+ 7. Return co-signed state
953
+
954
+ ### Checkpoint Flow
955
+ 1. Get latest signed state (both signatures)
956
+ 2. Determine blockchain ID from state's home ledger
957
+ 3. Get on-chain channel status
958
+ 4. Route based on transition type + status:
959
+ - Void channel -> `blockchainClient.create()`
960
+ - Existing channel -> `blockchainClient.checkpoint()`
961
+ - Finalize -> `blockchainClient.close()`
962
+ 5. Return transaction hash
963
+
964
+ ## Requirements
965
+
966
+ - **Node.js**: 20.0.0 or later
967
+ - **TypeScript**: 5.3.0 or later (for development)
968
+ - **Running Clearnode instance** or access to public node
969
+ - **Blockchain RPC endpoint** (for on-chain operations via `checkpoint()`)
970
+
971
+ ## Documentation
972
+
973
+ For complete documentation, visit [https://erc7824.org](https://erc7824.org)
974
+
975
+ ### Documentation Links
976
+
977
+ - [Quick Start Guide](https://erc7824.org/quick_start)
978
+ - [Channel Creation](https://erc7824.org/quick_start/initializing_channel)
979
+ - [ClearNode Connection](https://erc7824.org/quick_start/connect_to_the_clearnode)
980
+ - [Application Sessions](https://erc7824.org/quick_start/application_session)
981
+ - [Session Closure](https://erc7824.org/quick_start/close_session)
982
+
983
+ ## Build with AI
984
+
985
+ We have generated a [llms-full.txt](https://erc7824.org/llms-full.txt) file that converts all our documentation into a single markdown document following the [llmstxt.org](https://llmstxt.org/) standard.
986
+
987
+ ## License
988
+
989
+ Part of the Nitrolite project. See [LICENSE](../../LICENSE) for details.
990
+
991
+ ## Related Projects
992
+
993
+ - [Nitrolite Go SDK](../go/README.md) - Go implementation with same API
994
+ - [ERC-7824 Specification](https://eips.ethereum.org/EIPS/eip-7824) - Standard specification
995
+ - [Nitrolite Smart Contracts](../../contract/) - On-chain contracts
996
+
997
+ ---
998
+
999
+ **Built with Nitrolite** - Powering the next generation of scalable blockchain applications.