JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 8
  • Score
    100M100P100Q50760F
  • License MIT

TOON client for ILP-gated Nostr publishing with multi-hop routing and payment channels

Package Exports

  • @toon-protocol/client
  • @toon-protocol/client/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@toon-protocol/client) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@toon-protocol/client

High-level TypeScript client for publishing Nostr events to the TOON protocol — an ILP-gated Nostr relay that enables sustainable relay operation through micropayments.

What It Does

This client handles:

  • ILP Micropayments: Pay to publish Nostr events (read is free)
  • Payment Channels: Automatic on-chain channel creation with off-chain settlement via signed balance proofs
  • Unified Identity: One Nostr key = one EVM address (both use secp256k1, derived automatically)
  • Multi-Hop Routing: Publish to any destination address, not just your direct peer
  • Network Bootstrap: Automatically discover and register with ILP peers via NIP-02 follow lists
  • TOON Encoding: Native binary format for agent-friendly event encoding

Installation

pnpm add @toon-protocol/client @toon-protocol/core @toon-protocol/relay nostr-tools

Prerequisites

The client requires external services. Use docker-compose for local development:

# Start genesis node
docker compose -p toon-genesis -f docker-compose-genesis.yml up -d

# Verify services are healthy
curl http://localhost:8080/health  # ILP Connector (runtime)
curl http://localhost:8081/health  # ILP Connector (admin)
curl http://localhost:3100/health  # TOON BLS
# Nostr relay on ws://localhost:7100 (WebSocket, no HTTP endpoint)

# Stop infrastructure
docker compose -p toon-genesis -f docker-compose-genesis.yml down
Service Port Purpose
ILP Connector (Runtime) 8080 Routes ILP packets to relay
ILP Connector (Admin) 8081 Manages peer configuration
TOON BLS 3100 Validates events, calculates pricing, stores events
Nostr Relay 7100 WebSocket relay for peer discovery (kind:10032)

Quick Start

import { TOONClient } from '@toon-protocol/client';
import { generateSecretKey, getPublicKey, finalizeEvent } from 'nostr-tools/pure';
import { encodeEventToToon, decodeEventFromToon } from '@toon-protocol/relay';

// 1. Generate identity — one key gives you both Nostr and EVM identities
const secretKey = generateSecretKey();
const pubkey = getPublicKey(secretKey);

// 2. Create client
const client = new TOONClient({
  connectorUrl: 'http://localhost:8080',
  secretKey,
  ilpInfo: {
    pubkey,
    ilpAddress: `g.toon.${pubkey.slice(0, 8)}`,
    btpEndpoint: 'ws://localhost:3000',
  },
  toonEncoder: encodeEventToToon,
  toonDecoder: decodeEventFromToon,
});

// 3. Start (bootstrap network, discover peers)
await client.start();

// Your EVM address is derived from the same key — no separate config needed
console.log(`EVM address: ${client.getEvmAddress()}`);

// 4. Publish event to relay via ILP payment
const event = finalizeEvent(
  { kind: 1, content: 'Hello from TOON!', tags: [], created_at: Math.floor(Date.now() / 1000) },
  secretKey,
);

const result = await client.publishEvent(event);
if (result.success) {
  console.log(`Published: ${result.eventId}`);
}

// 5. Clean up
await client.stop();

Payment Channels

The client supports EVM-based payment channels for off-chain settlement. Your EVM identity is derived from your Nostr secretKey automatically — no separate EVM key needed.

Enabling Payment Channels

To use payment channels, add chain configuration. The client already has your EVM identity from secretKey:

const client = new TOONClient({
  connectorUrl: 'http://localhost:8080',
  secretKey,
  ilpInfo: { pubkey, ilpAddress: `g.toon.${pubkey.slice(0, 8)}`, btpEndpoint: 'ws://localhost:3000' },
  toonEncoder: encodeEventToToon,
  toonDecoder: decodeEventFromToon,

  // Add chain config to enable payment channels
  supportedChains: ['evm:anvil:31337'],
  chainRpcUrls: { 'evm:anvil:31337': 'http://localhost:8545' },
  settlementAddresses: { 'evm:anvil:31337': client.getEvmAddress()! },
  tokenNetworks: { 'evm:anvil:31337': '0xCafac3dD18aC6c6e92c921884f9E4176737C052c' },
  initialDeposit: '1000000000000000000', // 1 ETH in wei
});

await client.start();

// Channels are created automatically during bootstrap
const channels = client.getTrackedChannels();
console.log(`Tracking ${channels.length} payment channels`);

// Publish with signed balance proof
const channelId = channels[0];
const claim = await client.signBalanceProof(channelId, 1000n);
await client.publishEvent(event, { claim });

How It Works

  1. Bootstrap: Client discovers peers via NIP-02 and kind:10032 events
  2. Channel Creation: Opens on-chain payment channel using your derived EVM address
  3. Off-chain Payments: Signed balance proofs settle payments off-chain
  4. Auto-tracking: ChannelManager automatically tracks channels and increments nonces

Using a Separate EVM Key (Advanced)

If you need a different EVM identity than your Nostr key (e.g., hardware wallet or custodial key), pass evmPrivateKey explicitly:

const client = new TOONClient({
  // ... required config ...
  evmPrivateKey: '0x...', // Overrides the default derivation from secretKey
});

Documentation


Testing

Unit & Integration Tests

cd packages/client
pnpm test                 # Run all unit/integration tests
pnpm test:coverage        # Run with coverage report

E2E Tests

E2E tests require the genesis node infrastructure:

# Start infrastructure
docker compose -p toon-genesis -f docker-compose-genesis.yml up -d
sleep 10

# Run E2E tests
cd packages/client
pnpm test:e2e

See tests/e2e/README.md for detailed E2E setup.


Examples

See examples/client-example/ for standalone client examples:

  • 01 - Publish Event: Full client lifecycle with self-describing claims
  • 02 - Payment Channel Lifecycle: Multiple events with incrementing balance proofs


License

MIT