Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions sdk/ts-compat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
`@yellow-org/sdk-compat` is intentionally narrower than the published v0.5.3 package surface.

- **Preserved app-facing APIs**: the `NitroliteClient` facade, selected auth helpers, app-session signing helpers, and many app-facing types remain available for supported migration paths.
- **Transitional helper surfaces**: many legacy `create*Message` / `parse*Response` exports remain so imports can keep compiling during migration, but several are transitional shims rather than one-to-one v1 RPC mappings.
- **Transitional helper surfaces**: some legacy `create*Message` / `parse*Response` exports now emit real v1-compatible payloads inside the legacy `req`/`sig` envelope, while workflow-only helpers stay exported as fail-fast migration shims.
- **Unsupported full-package parity**: low-level internals, broad root-export parity, and every legacy helper being runtime-faithful are not promised by this package.

## Why
Expand Down Expand Up @@ -97,10 +97,10 @@ const assets = await client.getAssetsList();

### 4. Transfer off-chain

The compat `transfer(destination, allocations)` preserves the v0.5.3-style array-of-allocations signature. Each `TransferAllocation.amount` is a **raw-unit string** (smallest denomination). The compat layer divides by token decimals before delegating to the v1 SDK's `transfer(wallet, asset, Decimal)`:
The compat `transfer(destination, allocations)` preserves the v0.5.3-style array-of-allocations signature. Each `TransferAllocation.amount` is a **raw asset-unit string** using the asset's canonical decimals. The compat layer divides by asset decimals before delegating to the v1 SDK's `transfer(wallet, asset, Decimal)`:

```typescript
// 5 USDC = 5_000_000 raw units (6 decimals)
// 5 USDC = 5_000_000 raw asset units when USDC has 6 asset decimals
await client.transfer(recipientAddress, [
{ asset: 'usdc', amount: '5000000' },
]);
Expand Down Expand Up @@ -147,6 +147,7 @@ await client.close();
| `getEscrowChannel(escrowChannelId)` | Query an escrow channel by ID |
| `getChannelData(channelId)` | Full channel + state for a specific channel |
| `getLastAppSessionsListError()` | Last `getAppSessionsList()` error message (if any) |
| `getOpenChannels()` | Read current-chain open channel IDs from the ChannelHub |

### App Sessions

Expand All @@ -157,6 +158,8 @@ await client.close();
| `submitAppState(params)` | Submit state update (operate/deposit/withdraw/close) |
| `getAppDefinition(appSessionId)` | Get the definition for a session |

App-session allocation strings remain **human-readable decimal strings** such as `'0.01'`. They are not raw smallest-unit token strings.

### App Registry

| Method | Description |
Expand Down Expand Up @@ -190,6 +193,8 @@ await client.close();
|---|---|
| `transfer(destination, allocations)` | Off-chain transfer to another participant |

`TransferAllocation.amount` remains a **raw asset-unit string** using the asset's canonical decimals, for example `'5000000'` for 5 USDC when USDC has 6 asset decimals.

### Asset Resolution

| Method | Description |
Expand All @@ -202,6 +207,25 @@ await client.close();
| `parseAmount(tokenAddress, humanAmount)` | Convert human-readable string → raw bigint |
| `findOpenChannel(tokenAddress, chainId?)` | Find an open channel for a given token |

### Legacy On-Chain Helpers

| Method | Description |
|---|---|
| `approveTokens(tokenAddress, amount)` | Approve the current-chain ChannelHub using raw token units |
| `getTokenAllowance(tokenAddress)` | Read current-chain ChannelHub allowance in raw token units |
| `getTokenBalance(tokenAddress)` | Read current-chain wallet token balance in raw token units |

### Unsupported Legacy Gaps

These legacy methods remain intentionally unsupported because the v1 runtime no longer offers an honest one-to-one mapping:

- `createChannel(...)`
- `checkpointChannel(...)`
- `getAccountBalance(...)`
- `getChannelBalance(...)`

Workflow-style RPC helpers such as `createTransferMessage(...)`, `createCreateChannelMessage(...)`, `createCloseChannelMessage(...)`, and `createResizeChannelMessage(...)` are in the same category: they stay exported for migration, but now fail fast with migration guidance instead of silently approximating old behavior.

### Security Token Locking

| Method | Description |
Expand Down Expand Up @@ -377,32 +401,40 @@ await client.withdrawSecurityTokens(chainId, destinationWallet);

### Amount conventions

The compat layer accepts raw amounts (smallest token unit) and converts to human-readable `Decimal` before delegating to the v1 SDK.
The compat layer keeps the old amount conventions explicit instead of flattening them:

| Method group | Input type | Example: 100 tokens (18 decimals) |
|---|---|---|
| `deposit`, `withdrawal`, `lockSecurityTokens`, `approveSecurityToken`, `getLockedBalance` | Raw `bigint` | `100_000_000_000_000_000_000n` |
| `transfer` | Raw string via `TransferAllocation.amount` | `'100000000000000000000'` |
| `transfer` | Raw asset-unit string via `TransferAllocation.amount` | `'100000000000000000000'` |
| `createAppSession`, `closeAppSession`, `submitAppState` allocations | Human-readable decimal string | `'100.0'` |

> For direct access to the v1 SDK's human-readable `Decimal` API, use `client.innerClient`.

## RPC Stubs

The following functions remain exported primarily so legacy `create*Message` / `parse*Response` imports can keep compiling while an app migrates.
Many `create*` helpers are transitional shims rather than protocol-backed one-to-one v1 RPC mappings, and `parse*` helpers only do lightweight normalization of known response shapes.
Some `create*` helpers emit real live-v1 method names and payload shapes inside the legacy `req` / `sig` envelope. Workflow-only helpers fail fast with migration guidance instead of returning fake wire payloads. `parse*` helpers only do lightweight normalization of known response shapes.
Prefer `NitroliteClient` methods directly for new integrations:

```typescript
// Transitional compat exports:
// Direct v1-compatible helper mappings:
createGetChannelsMessage, parseGetChannelsResponse,
createGetLedgerBalancesMessage, parseGetLedgerBalancesResponse,
parseGetLedgerEntriesResponse, parseGetAppSessionsResponse,
createTransferMessage, createAppSessionMessage, parseCreateAppSessionResponse,
parseGetLedgerEntriesResponse, createGetAppSessionsMessage, parseGetAppSessionsResponse,
createGetAppDefinitionMessage, parseGetAppDefinitionResponse,
createAppSessionMessage, parseCreateAppSessionResponse,
createCloseAppSessionMessage, parseCloseAppSessionResponse,
createSubmitAppStateMessage, parseSubmitAppStateResponse,
createPingMessage,

// Migration-only shims that fail fast:
createTransferMessage,
createCreateChannelMessage, parseCreateChannelResponse,
createCloseChannelMessage, parseCloseChannelResponse,
createResizeChannelMessage, parseResizeChannelResponse,
createPingMessage,

// Generic normalizers:
convertRPCToClientChannel, convertRPCToClientState,
parseAnyRPCResponse, NitroliteRPC
```
Expand Down
23 changes: 22 additions & 1 deletion sdk/ts-compat/docs/migration-offchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,22 @@ parseCreateAppSessionResponse(raw);
```
**After:** `client.createAppSession(definition, allocations)`

`createAppSessionMessage` now emits a real `app_sessions.v1.create_app_session` payload inside the legacy `req` / `sig` envelope, but new integrations should still prefer `client.createAppSession(...)`.

### Close

**Before:** `createCloseAppSessionMessage` + send + parse
**After:** `client.closeAppSession(appSessionId, allocations)`

`createCloseAppSessionMessage` maps to `app_sessions.v1.submit_app_state` with `intent = close`, so it now requires an explicit `version` if you keep the helper path.

### Submit State

**Before:** `createSubmitAppStateMessage` + send
**After:** `client.submitAppState(params)`

`createSubmitAppStateMessage` also requires `params.version` for the live v1 mapping.

### Get Definition

**Before:** `createGetAppDefinitionMessage` + send + parse
Expand All @@ -47,11 +53,15 @@ await sendRequest(msg);
```
**After:** `client.transfer(destination, allocations)`

`createTransferMessage` remains exported only so old imports keep compiling, but it now fails fast with migration guidance because transfer is no longer a single direct v1 RPC helper. This is a deliberate runtime change from the old silent placeholder behavior.

## 4. Ledger Queries

**Before:** `createGetLedgerBalancesMessage` / `createGetLedgerEntriesMessage` + send + parse
**After:** `client.getBalances()`, `client.getLedgerEntries()`

`createGetLedgerBalancesMessage` now emits a real `user.v1.get_balances` request and requires the wallet/account parameter. `createGetAppSessionsMessage` and `createGetAppDefinitionMessage` likewise emit live v1 request shapes inside the legacy envelope.

## 5. Event Polling

v0.5.3 used WebSocket push events (`ChannelUpdate`, `BalanceUpdate`). v1 uses polling. The compat layer provides `EventPoller`:
Expand All @@ -70,4 +80,15 @@ poller.start();

## 6. RPC Compatibility Helpers

The `create*Message` and `parse*Response` exports still exist primarily so legacy imports can keep compiling while you migrate call sites. Treat them as transitional compatibility shims, not as proof of full one-to-one v1 RPC coverage. For new code, prefer `NitroliteClient` methods directly. Examples: `createGetChannelsMessage`, `parseGetChannelsResponse`, `createTransferMessage`, `createAppSessionMessage`, `createCloseAppSessionMessage`, etc.
The `create*Message` and `parse*Response` exports still exist primarily so legacy imports can keep compiling while you migrate call sites.

- Direct query/app-session helpers such as `createGetChannelsMessage`, `createGetLedgerBalancesMessage`, `createGetAppSessionsMessage`, `createGetAppDefinitionMessage`, `createAppSessionMessage`, `createSubmitAppStateMessage`, `createCloseAppSessionMessage`, and `createPingMessage` now emit live v1 method names and payload shapes inside the legacy envelope.
- Workflow helpers such as `createTransferMessage` stay exported but fail fast with migration guidance instead of returning fake wire payloads.
- `parse*Response` helpers only normalize known response fields; they do not recreate old payloads that the live v1 server no longer returns.

For new code, prefer `NitroliteClient` methods directly.

### Amount conventions

- `TransferAllocation.amount` remains a raw asset-unit string such as `'5000000'` for 5 USDC when USDC has 6 asset decimals.
- App-session allocation amounts in `createAppSession`, `closeAppSession`, and `submitAppState` remain human-readable decimal strings such as `'0.01'`.
25 changes: 13 additions & 12 deletions sdk/ts-compat/docs/migration-onchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ This guide covers on-chain operations when migrating from v0.5.3 to the compat l

```typescript
await approveToken(custody, tokenAddress, amount);
await sendRequest(createDepositMessage(signer.sign, { token: tokenAddress, amount }));
await sendRequest(createCreateChannelMessage(signer.sign, { token: tokenAddress, amount }));
```

Expand All @@ -18,6 +17,10 @@ await sendRequest(createCreateChannelMessage(signer.sign, { token: tokenAddress,
await client.deposit(tokenAddress, amount);
```

The legacy `createChannel()` client method and `createCreateChannelMessage(...)` helper still exist for migration, but they now throw with migration guidance instead of warning or fabricating a fake wire payload. Use `deposit(...)` or `depositAndCreateChannel(...)` instead.

`createCreateChannelMessage` remains exported so old imports keep compiling, but it now fails fast with migration guidance because channel creation is no longer a standalone protocol-backed RPC in v1.

## 2. Withdrawals

**Before (v0.5.3):** Manual close → checkpoint → withdraw
Expand All @@ -26,7 +29,6 @@ await client.deposit(tokenAddress, amount);
const closeMsg = await createCloseChannelMessage(signer.sign, { channel_id });
const raw = await sendRequest(closeMsg);
// ... checkpoint on-chain ...
await sendRequest(createWithdrawMessage(signer.sign, { token, amount }));
```

**After (compat):** Single call
Expand All @@ -35,24 +37,21 @@ await sendRequest(createWithdrawMessage(signer.sign, { token, amount }));
await client.withdrawal(tokenAddress, amount);
```

`createCloseChannelMessage` now fails fast with migration guidance instead of pretending to be a real v1 wire helper.

## 3. Channel Operations

Legacy channel helper imports may still exist to keep migration moving, but the supported path is the compat client methods below. Do not treat every legacy helper name as a protocol-backed one-to-one v1 RPC.

| Operation | v0.5.3 | Compat |
|-----------|--------|--------|
| Create | Explicit `createChannel()` | Implicit on first `deposit()` |
| Close | `createCloseChannelMessage` + send + parse | `client.closeChannel()` |
| Resize | `createResizeChannelMessage` + send + parse | `client.resizeChannel({ allocate_amount, token })` |
| Create | Explicit `createChannel()` (now throwing migration shim) | Implicit on first `deposit()` |
| Close | `createCloseChannelMessage` (now fail-fast shim) | `client.closeChannel()` |
| Resize | `createResizeChannelMessage` (now fail-fast shim) | `client.resizeChannel({ allocate_amount, token })` |

**Example — close:**

```typescript
// Before
const msg = await createCloseChannelMessage(signer.sign, { channel_id });
const raw = await sendRequest(msg);
const parsed = parseCloseChannelResponse(raw);

// After
await client.closeChannel();
```
Expand All @@ -66,7 +65,7 @@ const amount = 11_000_000n; // 11 USDC (6 decimals)
// Manual conversion for display: formatUnits(amount, 6)
```

**After (compat):** App-facing methods still accept raw token amounts, and the compat layer handles the conversion needed to call the v1 SDK correctly
**After (compat):** On-chain app-facing methods still accept raw token amounts, and the compat layer handles the conversion needed to call the v1 SDK correctly

```typescript
// Raw BigInt still works
Expand All @@ -77,7 +76,9 @@ const formatted = client.formatAmount(tokenAddress, 11_000_000n); // "11.0"
const parsed = client.parseAmount(tokenAddress, "11.0"); // 11_000_000n
```

For transfers and allocations, compat accepts human-readable strings: `{ asset: 'usdc', amount: '5.0' }`.
Transfer allocations still use raw asset-unit strings, for example `{ asset: 'usdc', amount: '5000000' }` for 5 USDC when USDC has 6 asset decimals.

App-session allocations are different: those remain human-readable decimal strings such as `{ asset: 'usdc', amount: '5.0' }`.

## 5. Contract Addresses

Expand Down
6 changes: 3 additions & 3 deletions sdk/ts-compat/docs/migration-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ npm install @yellow-org/sdk viem
| `import { createGetChannelsMessage, parseGetChannelsResponse } from '@layer-3/nitrolite'` | `import { NitroliteClient } from '@yellow-org/sdk-compat'` |
| Types: `AppSession`, `LedgerChannel`, `RPCAppDefinition` | Many app-facing types remain re-exported from `@yellow-org/sdk-compat` |

For **types**, many app-facing imports only need a package-name swap. For **functions**, prefer client methods instead of `create*Message` / `parse*Response`. Some legacy helper imports remain exported only as transitional migration shims.
For **types**, many app-facing imports only need a package-name swap. For **functions**, prefer client methods instead of `create*Message` / `parse*Response`. Some legacy helper imports remain exported as direct v1-compatible request builders; workflow-style helpers stay exported as fail-fast migration shims so imports keep compiling while call sites move.

## 4. The Key Pattern Change

Expand Down Expand Up @@ -53,7 +53,7 @@ const channels = await client.getChannels();
|---------|--------|--------|
| WebSocket | App creates and manages `WebSocket` | Managed internally by the client |
| Signing | App passes `signer.sign` into every message | Internal — client uses `WalletClient` |
| Amounts | Raw `BigInt` everywhere | Compat keeps raw-unit app-facing inputs and handles the v1 bridge internally |
| Amounts | Raw `BigInt` everywhere | Compat keeps legacy amount conventions explicit: transfers stay raw asset-unit strings, app-session allocations stay human-decimal strings |
| Contract addresses | Manual config | Fetched from nitronode `get_config` |
| Channel creation | Explicit `createChannel()` | Implicit on first `deposit()` |

Expand All @@ -79,7 +79,7 @@ const balances = await client.getBalances();
const sessions = await client.getAppSessionsList();

// Transfer
await client.transfer(recipientAddress, [{ asset: 'usdc', amount: '5.0' }]);
await client.transfer(recipientAddress, [{ asset: 'usdc', amount: '5000000' }]);

// Cleanup
await client.closeChannel();
Expand Down
Loading
Loading