Skip to content
This repository was archived by the owner on Jul 31, 2025. It is now read-only.
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
12 changes: 10 additions & 2 deletions docs/nitrolite_client/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const nitroliteClient = new NitroliteClient({
guestAddress: '0x...',
tokenAddress: '0x...'
},
chainId: 137, // Polygon mainnet
challengeDuration: 100n
});

Expand All @@ -59,8 +60,15 @@ const { channelId, initialState, txHash } = await nitroliteClient.createChannel(

// 3. Resize the channel when needed
const resizeTxHash = await nitroliteClient.resizeChannel({
channelId,
candidateState: updatedState
resizeState: {
channelId,
stateData: '0x5678',
allocations: newAllocations,
version: 2n,
intent: StateIntent.RESIZE,
serverSignature: signature
},
proofStates: []
});

// 4. Close the channel
Expand Down
30 changes: 25 additions & 5 deletions docs/nitrolite_client/methods.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,15 @@ The deposit phase includes methods for managing funds in the custody contract an
params={[{ name: "params", type: "ResizeChannelParams" }]}
returns="Promise<Hash>"
example={`await client.resizeChannel({
channelId, // The ID of the channel to resize
candidateState // The latest state reflecting the new desired total allocation
resizeState: {
channelId,
stateData: '0x5678',
allocations: newAllocations,
version: 2n,
intent: StateIntent.RESIZE,
serverSignature: signature
},
proofStates: []
});`}
/>

Expand Down Expand Up @@ -176,7 +183,13 @@ For Account Abstraction support and transaction preparation methods, see the [Ab
import { NitroliteClient } from '@erc7824/nitrolite';

// Initialize the client
const client = new NitroliteClient({/* config */});
const client = new NitroliteClient({
publicClient,
walletClient,
addresses: { custody, adjudicator, guestAddress, tokenAddress },
chainId: 137,
challengeDuration: 100n
});

// 1. Deposit funds
const depositTxHash = await client.deposit(1000000n);
Expand All @@ -193,8 +206,15 @@ console.log(`Locked in channels: ${accountInfo.locked}`);

// 4. Later, resize the channel
const resizeTxHash = await client.resizeChannel({
channelId,
candidateState: updatedState // With new allocations
resizeState: {
channelId,
stateData: '0x5678',
allocations: newAllocations,
version: 2n,
intent: StateIntent.RESIZE,
serverSignature: signature
},
proofStates: []
});

// 5. Close the channel
Expand Down
89 changes: 59 additions & 30 deletions docs/nitrolite_client/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,19 +97,32 @@ Represents a complete state channel state, including allocations and signatures.

```typescript
interface NitroliteClientConfig {
// Required: viem PublicClient for reading blockchain data
/** The viem PublicClient for reading blockchain data. */
publicClient: PublicClient;

// Required: viem WalletClient for sending transactions and account context

/**
* The viem WalletClient used for:
* 1. Sending on-chain transactions in direct execution methods (e.g., `client.deposit`).
* 2. Providing the 'account' context for transaction preparation (`client.txPreparer`).
* 3. Signing off-chain states *if* `stateWalletClient` is not provided.
*/
walletClient: WalletClient<Transport, Chain, ParseAccount<Account>>;

// Optional: Separate wallet client for signing states

/**
* Optional: A separate viem WalletClient used *only* for signing off-chain state updates (`signMessage`).
* Provide this if you want to use a different key (e.g., a "hot" key from localStorage)
* for state signing than the one used for on-chain transactions.
* If omitted, `walletClient` will be used for state signing.
*/
stateWalletClient?: WalletClient<Transport, Chain, ParseAccount<Account>>;
// Required: Contract addresses

/** Contract addresses required by the SDK. */
addresses: ContractAddresses;

// Required: Challenge duration in seconds

/** Chain ID for the channel */
chainId: number;

/** Optional: Default challenge duration (in seconds) for new channels. Defaults to 0 if omitted. */
challengeDuration?: bigint;
}
```
Expand Down Expand Up @@ -162,9 +175,15 @@ interface ChallengeChannelParams {
}

interface ResizeChannelParams {
channelId: ChannelId; // Channel ID to resize
candidateState: State; // State with new allocations
proofStates?: State[]; // Optional proof states
resizeState: {
channelId: ChannelId;
stateData: Hex;
allocations: [Allocation, Allocation];
version: bigint;
intent: StateIntent;
serverSignature: Signature;
};
proofStates: State[];
}
```

Expand Down Expand Up @@ -194,7 +213,6 @@ Parameters for collaboratively closing a channel.
```typescript
interface AccountInfo {
available: bigint; // Available funds in the custody contract
locked: bigint; // Funds locked in channels
channelCount: bigint; // Number of channels
}
```
Expand Down Expand Up @@ -230,10 +248,10 @@ const allowance: bigint = await client.getTokenAllowance()

```typescript
// Create channel
const result: {
channelId: ChannelId;
initialState: State;
txHash: Hash
const result: {
channelId: ChannelId;
initialState: State;
txHash: Hash
} = await client.createChannel({
initialAllocationAmounts: [bigint, bigint],
stateData: Hex
Expand All @@ -245,20 +263,31 @@ const result: {
```typescript
// Resize
await client.resizeChannel({
channelId: ChannelId,
candidateState: State
resizeState: {
channelId: ChannelId,
stateData: Hex,
allocations: [Allocation, Allocation],
version: bigint,
intent: StateIntent,
serverSignature: Signature
},
proofStates: State[]
}): Promise<Hash>

// State is structured as:
const state: State = {
intent: StateIntent.RESIZE,
version: 2n, // Incremented from previous
data: '0x1234',
allocations: [
{ destination: addr1, token: tokenAddr, amount: 600000n },
{ destination: addr2, token: tokenAddr, amount: 400000n }
],
sigs: [signature1, signature2]
// Resize is structured as:
const resizeParams: ResizeChannelParams = {
resizeState: {
channelId,
stateData: '0x1234',
allocations: [
{ destination: addr1, token: tokenAddr, amount: 600000n },
{ destination: addr2, token: tokenAddr, amount: 400000n }
],
version: 2n, // Incremented from previous
intent: StateIntent.RESIZE,
serverSignature: signature
},
proofStates: []
}
```

Expand Down Expand Up @@ -343,4 +372,4 @@ const finalState = {
],
sigs: [userSig, guestSig]
};
```
```
71 changes: 40 additions & 31 deletions docs/nitrolite_rpc/message_creation_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,36 +115,35 @@ Functions for retrieving information from the broker.

<MethodDetails
name="createGetConfigMessage"
description="Creates the signed, stringified message body for a 'get_config' request to retrieve broker or channel configuration."
description="Creates the signed, stringified message body for a 'get_config' request to retrieve broker configuration."
params={[
{ name: "signer", type: "MessageSigner", description: "The function to sign the request payload." },
{ name: "channelId", type: "AccountID", description: "The Channel ID or a general scope for configuration." },
{ name: "requestId", type: "RequestID", description: "Optional request ID. Defaults to a generated ID.", optional: true },
{ name: "timestamp", type: "Timestamp", description: "Optional timestamp. Defaults to the current time.", optional: true }
]}
returns="Promise<string>"
example={`
import { createGetConfigMessage } from "@erc7824/nitrolite";
// Assuming 'signer' and 'channelId' are defined
const getConfigMsg = await createGetConfigMessage(signer, channelId);
// Assuming 'signer' is defined
const getConfigMsg = await createGetConfigMessage(signer);
// Send getConfigMsg via WebSocket
`}
/>

<MethodDetails
name="createGetLedgerBalancesMessage"
description="Creates the signed, stringified message body for a 'get_ledger_balances' request to fetch balances for a specific ledger channel."
description="Creates the signed, stringified message body for a 'get_ledger_balances' request to fetch balances for a specific participant."
params={[
{ name: "signer", type: "MessageSigner", description: "The function to sign the request payload." },
{ name: "channelId", type: "AccountID", description: "The Channel ID to get ledger balances for." },
{ name: "participant", type: "Address", description: "The participant address to get ledger balances for." },
{ name: "requestId", type: "RequestID", description: "Optional request ID. Defaults to a generated ID.", optional: true },
{ name: "timestamp", type: "Timestamp", description: "Optional timestamp. Defaults to the current time.", optional: true }
]}
returns="Promise<string>"
example={`
import { createGetLedgerBalancesMessage } from "@erc7824/nitrolite";
// Assuming 'signer' and 'channelId' are defined
const getBalancesMsg = await createGetLedgerBalancesMessage(signer, channelId);
// Assuming 'signer' and 'participant' are defined
const getBalancesMsg = await createGetLedgerBalancesMessage(signer, participant);
// Send getBalancesMsg via WebSocket
`}
/>
Expand All @@ -154,19 +153,37 @@ const getBalancesMsg = await createGetLedgerBalancesMessage(signer, channelId);
description="Creates the signed, stringified message body for a 'get_app_definition' request to retrieve the definition of a specific application."
params={[
{ name: "signer", type: "MessageSigner", description: "The function to sign the request payload." },
{ name: "appId", type: "AccountID", description: "The Application ID to get the definition for." },
{ name: "appSessionId", type: "AccountID", description: "The Application Session ID to get the definition for." },
{ name: "requestId", type: "RequestID", description: "Optional request ID. Defaults to a generated ID.", optional: true },
{ name: "timestamp", type: "Timestamp", description: "Optional timestamp. Defaults to the current time.", optional: true }
]}
returns="Promise<string>"
example={`
import { createGetAppDefinitionMessage } from "@erc7824/nitrolite";
// Assuming 'signer' and 'appId' are defined
const getAppDefMsg = await createGetAppDefinitionMessage(signer, appId);
// Assuming 'signer' and 'appSessionId' are defined
const getAppDefMsg = await createGetAppDefinitionMessage(signer, appSessionId);
// Send getAppDefMsg via WebSocket
`}
/>

<MethodDetails
name="createGetChannelsMessage"
description="Creates the signed, stringified message body for a 'get_channels' request to retrieve channels for a specific participant."
params={[
{ name: "signer", type: "MessageSigner", description: "The function to sign the request payload." },
{ name: "participant", type: "Address", description: "The participant address to get channels for." },
{ name: "requestId", type: "RequestID", description: "Optional request ID. Defaults to a generated ID.", optional: true },
{ name: "timestamp", type: "Timestamp", description: "Optional timestamp. Defaults to the current time.", optional: true }
]}
returns="Promise<string>"
example={`
import { createGetChannelsMessage } from "@erc7824/nitrolite";
// Assuming 'signer' and 'participant' are defined
const getChannelsMsg = await createGetChannelsMessage(signer, participant);
// Send getChannelsMsg via WebSocket
`}
/>

## Application Session Management

Functions for creating and closing application sessions (state channels).
Expand All @@ -177,15 +194,14 @@ Functions for creating and closing application sessions (state channels).
params={[
{ name: "signer", type: "MessageSigner", description: "The function to sign the request payload." },
{ name: "params", type: "CreateAppSessionRequest[]", description: "An array of parameters defining the application session(s) to be created. See RPC Type Definitions for `CreateAppSessionRequest` structure." },
{ name: "intent", type: "Intent", description: "The initial allocation intent for the application session." },
{ name: "requestId", type: "RequestID", description: "Optional request ID. Defaults to a generated ID.", optional: true },
{ name: "timestamp", type: "Timestamp", description: "Optional timestamp. Defaults to the current time.", optional: true }
]}
returns="Promise<string>"
example={`
import { createAppSessionMessage, Intent } from "@erc7824/nitrolite";
// Assuming 'signer', 'appSessionParams', and 'initialIntent' are defined
const createAppMsg = await createAppSessionMessage(signer, appSessionParams, initialIntent);
import { createAppSessionMessage } from "@erc7824/nitrolite";
// Assuming 'signer' and 'appSessionParams' are defined
const createAppMsg = await createAppSessionMessage(signer, appSessionParams);
// Send createAppMsg via WebSocket
`}
/>
Expand All @@ -196,15 +212,14 @@ const createAppMsg = await createAppSessionMessage(signer, appSessionParams, ini
params={[
{ name: "signer", type: "MessageSigner", description: "The function to sign the request payload." },
{ name: "params", type: "CloseAppSessionRequest[]", description: "An array of parameters defining the application session(s) to be closed, including final allocations. See RPC Type Definitions for `CloseAppSessionRequest` structure." },
{ name: "intent", type: "Intent", description: "The final allocation intent for the application session." },
{ name: "requestId", type: "RequestID", description: "Optional request ID. Defaults to a generated ID.", optional: true },
{ name: "timestamp", type: "Timestamp", description: "Optional timestamp. Defaults to the current time.", optional: true }
]}
returns="Promise<string>"
example={`
import { createCloseAppSessionMessage, Intent } from "@erc7824/nitrolite";
// Assuming 'signer', 'closeParams', and 'finalIntent' are defined
const closeAppMsg = await createCloseAppSessionMessage(signer, closeParams, finalIntent);
import { createCloseAppSessionMessage } from "@erc7824/nitrolite";
// Assuming 'signer' and 'closeParams' are defined
const closeAppMsg = await createCloseAppSessionMessage(signer, closeParams);
// Send closeAppMsg via WebSocket
`}
/>
Expand All @@ -218,16 +233,16 @@ Function for sending messages within an active application session.
description="Creates the signed, stringified message body for sending a generic 'message' within an active application session (state channel). This is used for off-chain state updates and other application-specific communication."
params={[
{ name: "signer", type: "MessageSigner", description: "The function to sign the request payload." },
{ name: "appId", type: "AccountID", description: "The Application ID (state channel ID) the message is scoped to." },
{ name: "appSessionId", type: "Hex", description: "The Application Session ID the message is scoped to." },
{ name: "messageParams", type: "any[]", description: "The actual message content/parameters being sent, specific to the application logic." },
{ name: "requestId", type: "RequestID", description: "Optional request ID. Defaults to a generated ID.", optional: true },
{ name: "timestamp", type: "Timestamp", description: "Optional timestamp. Defaults to the current time.", optional: true }
]}
returns="Promise<string>"
example={`
import { createApplicationMessage } from "@erc7824/nitrolite";
// Assuming 'signer', 'appId', and 'appSpecificMessageData' are defined
const appMsg = await createApplicationMessage(signer, appId, [appSpecificMessageData]);
// Assuming 'signer', 'appSessionId', and 'appSpecificMessageData' are defined
const appMsg = await createApplicationMessage(signer, appSessionId, [appSpecificMessageData]);
// Send appMsg via WebSocket
`}
/>
Expand All @@ -249,8 +264,8 @@ Functions for managing the underlying ledger channels (direct channels with the
returns="Promise<string>"
example={`
import { createCloseChannelMessage } from "@erc7824/nitrolite";
// Assuming 'signer', 'channelId', and 'destinationAddress' are defined
const closeChannelMsg = await createCloseChannelMessage(signer, channelId, destinationAddress);
// Assuming 'signer', 'channelId', and 'fundDestination' are defined
const closeChannelMsg = await createCloseChannelMessage(signer, channelId, fundDestination);
// Send closeChannelMsg via WebSocket
`}
/>
Expand All @@ -272,12 +287,6 @@ const resizeMsg = await createResizeChannelMessage(signer, resizeParams);
// Send resizeMsg via WebSocket
`}
/>
// ...existing code...
// Assuming 'signer' and 'resizeParams' are defined
const resizeMsg = await createResizeChannelMessage(signer, resizeParams);
// Send resizeMsg via WebSocket
`}
/>

## Advanced: Creating a Local Signer for Development

Expand Down Expand Up @@ -361,7 +370,7 @@ export const createEthersSigner = (privateKey: string): WalletSigner => {
const messageToSign = JSON.stringify(payload);
const messageHash = ethers.utils.id(messageToSign); // ethers.utils.id performs keccak256
const messageBytes = ethers.utils.arrayify(messageHash);

const flatSignature = await wallet._signingKey().signDigest(messageBytes);
const signature = ethers.utils.joinSignature(flatSignature);
return signature as Hex;
Expand Down
4 changes: 2 additions & 2 deletions docs/nitrolite_rpc/rpc_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ const pingRequestMessage: NitroliteRPCMessage = {
};

// Example Application-Specific Request
const appActionData: RequestData = [2, "app_action", [{ move: "rock" }], Date.now()];
const appActionData: RequestData = [2, "message", [{ move: "rock" }], Date.now()];
const appActionMessage: ApplicationRPCMessage = {
acc: "0xAppChannelId...",
sid: "0xAppSessionId...",
req: appActionData,
// sig: ["0xSignature..."]
};
Expand Down