ERC7824
Nitrolite ClientAdvanced

Advanced Usage

Advanced topics for working with the NitroliteClient

Advanced Usage

This section covers advanced topics for working with the @erc7824/nitrolite SDK. These are intended for developers who need deeper control over the state channel operations or want to integrate with specialized systems.

Available Topics

Low-level Services

The NitroliteClient is built on top of specialized services that can be used directly for more fine-grained control:

  • NitroliteService - Core service for interacting with the custody contract and managing channels
  • Erc20Service - Service for interacting with ERC20 tokens

Account Abstraction Integration

  • Abstract Accounts - Using NitroliteClient with ERC-4337 Account Abstraction for smart contract wallets

When to Use Advanced Features

Consider using the advanced features when:

  1. Building custom workflows that require more control than the high-level NitroliteClient API provides
  2. Integrating with smart contract wallets or other account abstraction systems
  3. Implementing specialized monitoring or management systems for state channels
  4. Developing cross-chain applications that require custom handling of state channel operations
  5. Optimizing gas usage through transaction batching and other techniques

Example: Direct Service Usage

While using the high-level NitroliteClient is recommended for most applications, here's how you can work directly with the services:

import { 
  NitroliteService, 
  Erc20Service, 
  getChannelId,
  signState 
} from '@erc7824/nitrolite';

// Initialize services
const nitroliteService = new NitroliteService(
  publicClient,
  addresses,
  walletClient,
  account.address
);

const erc20Service = new Erc20Service(
  publicClient,
  walletClient
);

// Check token allowance
const allowance = await erc20Service.getTokenAllowance(
  tokenAddress,
  account.address,
  addresses.custody
);

// Approve tokens if needed
if (allowance < depositAmount) {
  await erc20Service.approve(tokenAddress, addresses.custody, depositAmount);
}

// Deposit funds
await nitroliteService.deposit(tokenAddress, depositAmount);

// Create channel with custom parameters
const channelNonce = generateChannelNonce(account.address);
const channel = {
  participants: [account.address, counterpartyAddress],
  adjudicator: addresses.adjudicator,
  challenge: 100n, // Challenge duration in seconds
  nonce: channelNonce
};

// Prepare initial state
const initialState = {
  intent: StateIntent.INITIALIZE,
  version: 0n,
  data: '0x1234', // Application-specific data
  allocations: [
    { destination: account.address, token: tokenAddress, amount: 700000n },
    { destination: counterpartyAddress, token: tokenAddress, amount: 300000n }
  ],
  sigs: [] // Will be filled with signatures
};

// Sign the state
const channelId = getChannelId(channel);
const stateHash = getStateHash(channelId, initialState);
const signature = await signState(walletClient, stateHash);
initialState.sigs = [signature];

// Create the channel
await nitroliteService.createChannel(channel, initialState);

Example: Complex Transaction Preparation

For applications using Account Abstraction, you can prepare complex transaction sequences:

import { NitroliteClient, NitroliteTransactionPreparer } from '@erc7824/nitrolite';

// Initialize client
const client = new NitroliteClient({/* config */});

// Access the transaction preparer directly
const txPreparer = client.txPreparer;

// Prepare a complete sequence (approve, deposit, create channel)
const allTxs = [];

// 1. Check and prepare token approval if needed
const allowance = await client.getTokenAllowance();
if (allowance < depositAmount) {
  const approveTx = await txPreparer.prepareApproveTokensTransaction(depositAmount);
  allTxs.push(approveTx);
}

// 2. Prepare deposit
const depositTx = await txPreparer.prepareDepositTransactions(depositAmount);
allTxs.push(...depositTx);

// 3. Prepare channel creation
const createChannelTx = await txPreparer.prepareCreateChannelTransaction({
  initialAllocationAmounts: [700000n, 300000n],
  stateData: '0x1234'
});
allTxs.push(createChannelTx);

// 4. Use with your Account Abstraction provider
await aaProvider.sendUserOperation({
  userOperations: allTxs.map(tx => ({
    target: tx.to,
    data: tx.data,
    value: tx.value || 0n
  }))
});

These advanced techniques give you greater flexibility and control over the state channel operations, but they also require a deeper understanding of the underlying protocol.