rpc

package
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2026 License: MIT Imports: 14 Imported by: 0

README

RPC Package

The pkg/rpc package provides the core data structures and utilities for the Nitrolite Node RPC protocol. This package implements a secure RPC communication protocol designed for blockchain and distributed systems with strong typing, efficient encoding, and clear error handling.

Overview

Protocol Features
  • Versioned API: Clear API versioning with {group}.v{version}.{action} method naming
  • Type Safety: Strongly-typed request/response structures for all operations
  • WebSocket Transport: Persistent connections with automatic reconnection
  • Error Handling: Explicit error types with MsgTypeRespErr
Client Features
  • High-Level Client: Type-safe methods for all RPC operations
  • WebSocket Transport: Persistent connection with keep-alive
  • Channel Management: Query and submit channel states
  • Application Sessions: Multi-party state channel applications
  • Session Keys: Register and manage session keys
Server Features
  • RPC Server: Complete server implementation with WebSocket transport
  • Handler Registration: Simple method-based request routing
  • Middleware Support: Composable request processing pipeline
  • Handler Groups: Organize endpoints with shared middleware
  • Connection Management: Automatic connection lifecycle handling

Core Components

Messages

The protocol uses four message types:

  • MsgTypeReq (1): Request message from client
  • MsgTypeResp (2): Success response from server
  • MsgTypeEvent (3): Server-initiated event notification
  • MsgTypeRespErr (4): Error response from server

All messages share a common structure with Type, RequestID, Method, Payload, and Timestamp.

Message Structure

Messages are the fundamental unit of communication:

type Message struct {
    Type      MsgType  // Message type: 1=Req, 2=Resp, 3=Event, 4=RespErr
    RequestID uint64   // Unique request identifier
    Method    string   // RPC method name (e.g., "node.v1.ping")
    Payload   Payload  // Method parameters or response data
    Timestamp uint64   // Unix milliseconds timestamp
}

Messages use a compact JSON array encoding for efficiency:

[1, 12345, "node.v1.get_config", {}, 1634567890123]

This format: [Type, RequestID, Method, Payload, Timestamp]

API Versioning

All RPC methods follow a versioned naming convention:

{group}.v{version}.{action}

Examples:

  • node.v1.ping - Node group, version 1, ping action
  • channels.v1.get_channels - Channels group, version 1, get channels action
  • user.v1.get_balances - User group, version 1, get balances action

API groups:

  • node: Node configuration and connectivity
  • channels: Payment channel management and state
  • app_sessions: Application session operations
  • session_keys: Session key management
  • user: User balances and transactions
Type Naming

All V1 API types follow the convention: {Group}V{Version}{Name}{Request|Response}

Examples:

  • NodeV1PingRequest / NodeV1PingResponse
  • ChannelsV1GetChannelsRequest / ChannelsV1GetChannelsResponse
  • UserV1GetBalancesRequest / UserV1GetBalancesResponse
Error Handling

Error responses use MsgTypeRespErr and preserve the original request method:

// Success response
Message{Type: MsgTypeResp, Method: "node.v1.ping", ...}

// Error response
Message{Type: MsgTypeRespErr, Method: "node.v1.ping", Payload: {"error": "..."}}

The package provides explicit error types for client communication:

// Client-facing error - will be sent in response
if amount < 0 {
    return rpc.Errorf("invalid amount: cannot be negative")
}

// Internal error - generic message sent to client
if err := db.Save(); err != nil {
    return fmt.Errorf("database error: %w", err)
}

Installation

import "github.com/layer-3/nitrolite/pkg/rpc"

Server Usage

Creating an RPC Server
import (
    "github.com/layer-3/nitrolite/pkg/rpc"
    "github.com/layer-3/nitrolite/pkg/log"
)

// Create server configuration
config := rpc.WebsocketNodeConfig{
    Logger: logger,  // Required: for structured logging

    // Connection lifecycle callbacks
    OnConnectHandler: func(send rpc.SendResponseFunc) {
        log.Info("New connection established")
    },
    OnDisconnectHandler: func(wallet string) {
        log.Info("Connection closed", "wallet", wallet)
    },
}

// Create the RPC node
node, err := rpc.NewWebsocketNode(config)
if err != nil {
    log.Fatal("Failed to create node", "error", err)
}

// Register handlers (node.v1.ping is built-in)
node.Handle("node.v1.get_config", handleGetConfig)
node.Handle("user.v1.get_balances", handleGetBalances)

// Add global middleware
node.Use(loggingMiddleware)
node.Use(rateLimitMiddleware)

// Create groups for organized endpoints
channelsV1Group := node.NewGroup("channels.v1")
channelsV1Group.Handle("channels.v1.submit_state", handleSubmitState)

// Start the server
http.Handle("/ws", node)
log.Fatal(http.ListenAndServe(":8080", nil))
Writing Handlers

Handlers process RPC requests and generate responses:

func handleGetBalances(c *rpc.Context) {

    // Extract and validate parameters
    var req rpc.UserV1GetBalancesRequest
    if err := c.Request.Payload.Translate(&req); err != nil {
        c.Fail(nil, "invalid parameters")
        return
    }

    // Access connection storage
    if lastCheck, ok := c.Storage.Get("last_balance_check"); ok {
        log.Debug("Last balance check", "time", lastCheck)
    }
    c.Storage.Set("last_balance_check", time.Now())

    // Process the request
    balances, err := ledger.GetBalances(req.Wallet)
    if err != nil {
        log.Error("Failed to get balances", "error", err)
        c.Fail(err, "failed to retrieve balances")
        return
    }

    // Create response
    resp := rpc.UserV1GetBalancesResponse{
        Balances: balances,
    }
    respPayload, _ := rpc.NewPayload(resp)

    // Send successful response
    c.Succeed("user.v1.get_balances", respPayload)
}
Writing Middleware

Middleware can process requests before/after handlers:

func loggingMiddleware(c *rpc.Context) {
    start := time.Now()
    method := c.Request.Method

    // Pre-processing
    log.Info("Request started",
        "method", method,
        "requestID", c.Request.RequestID)

    // Continue to next handler
    c.Next()

    // Post-processing
    duration := time.Since(start)
    log.Info("Request completed",
        "method", method,
        "requestID", c.Request.RequestID,
        "duration", duration)
}

func rateLimitMiddleware(c *rpc.Context) {
    key := fmt.Sprintf("rate_limit_%s", userID)

    // Get current count
    count := 0
    if val, ok := c.Storage.Get(key); ok {
        count = val.(int)
    }

    if count >= 100 {
        c.Fail(nil, "rate limit exceeded")
        return
    }

    // Increment and continue
    c.Storage.Set(key, count+1)
    c.Next()
}

Client Usage

Quick Start
import "github.com/layer-3/nitrolite/pkg/rpc"

// Create client
dialer := rpc.NewWebsocketDialer(rpc.DefaultWebsocketDialerConfig)
client := rpc.NewClient(dialer)

// Set up event handlers (optional)
go func() {
    for event := range dialer.EventCh() {
        if event == nil {
            break
        }
        log.Info("Received event", "method", event.Method)
    }
}()

// Connect to server
ctx := context.Background()
err := client.Start(ctx, "wss://clearnode-sandbox.yellow.org/v1/ws", func(err error) {
    if err != nil {
        log.Error("Connection closed", "error", err)
    }
})
if err != nil {
    log.Fatal("Failed to start client", "error", err)
}

// Make RPC calls
err = client.NodeV1Ping(ctx)
if err != nil {
    log.Error("Ping failed", "error", err)
}

config, err := client.NodeV1GetConfig(ctx)
if err != nil {
    log.Fatal(err)
}
log.Info("Connected to node", "address", config.NodeAddress)
Available Client Methods
Node Methods
// Ping the server
err := client.NodeV1Ping(ctx)

// Get node configuration
config, err := client.NodeV1GetConfig(ctx)

// Get supported assets (optional chain filter)
chainID := uint32(1)
assets, err := client.NodeV1GetAssets(ctx, rpc.NodeV1GetAssetsRequest{
    ChainID: &chainID,
})
User Methods
// Get user balances
balances, err := client.UserV1GetBalances(ctx, rpc.UserV1GetBalancesRequest{
    Wallet: walletAddress,
})

// Get transactions
txs, err := client.UserV1GetTransactions(ctx, rpc.UserV1GetTransactionsRequest{
    Wallet: walletAddress,
})
Channel Methods
// Get home channel
homeChannel, err := client.ChannelsV1GetHomeChannel(ctx, rpc.ChannelsV1GetHomeChannelRequest{
    Wallet: walletAddress,
    Asset:  "usdc",
})

// Get escrow channel
escrowChannel, err := client.ChannelsV1GetEscrowChannel(ctx, rpc.ChannelsV1GetEscrowChannelRequest{
    Wallet: walletAddress,
    Asset:  "usdc",
})

// Get all channels
channels, err := client.ChannelsV1GetChannels(ctx, rpc.ChannelsV1GetChannelsRequest{
    Wallet: walletAddress,
})

// Get latest state
state, err := client.ChannelsV1GetLatestState(ctx, rpc.ChannelsV1GetLatestStateRequest{
    Wallet: walletAddress,
    Asset:  "usdc",
})

// Get states with filters
states, err := client.ChannelsV1GetStates(ctx, rpc.ChannelsV1GetStatesRequest{
    Wallet: walletAddress,
    Asset:  &asset,
})

// Request channel creation
creation, err := client.ChannelsV1RequestCreation(ctx, rpc.ChannelsV1RequestCreationRequest{
    Wallet: walletAddress,
    Asset:  "usdc",
})

// Submit state
submitResp, err := client.ChannelsV1SubmitState(ctx, rpc.ChannelsV1SubmitStateRequest{
    State: stateData,
})
App Session Methods
// Get app definition
appDef, err := client.AppSessionsV1GetAppDefinition(ctx, rpc.AppSessionsV1GetAppDefinitionRequest{
    AppSessionID: sessionID,
})

// Get app sessions
sessions, err := client.AppSessionsV1GetAppSessions(ctx, rpc.AppSessionsV1GetAppSessionsRequest{
    Wallet: walletAddress,
})

// Create app session
session, err := client.AppSessionsV1CreateAppSession(ctx, rpc.AppSessionsV1CreateAppSessionRequest{
    Definition: definition,
})

// Close app session
closeResp, err := client.AppSessionsV1CloseAppSession(ctx, rpc.AppSessionsV1CloseAppSessionRequest{
    AppSessionID: sessionID,
})

// Submit deposit state
depositResp, err := client.AppSessionsV1SubmitDepositState(ctx, rpc.AppSessionsV1SubmitDepositStateRequest{
    AppSessionID: sessionID,
    State:        stateData,
})

// Submit app state
appStateResp, err := client.AppSessionsV1SubmitAppState(ctx, rpc.AppSessionsV1SubmitAppStateRequest{
    AppSessionID: sessionID,
    State:        stateData,
})
Session Key Methods
// Register session key
registerResp, err := client.SessionKeysV1Register(ctx, rpc.SessionKeysV1RegisterRequest{
    Wallet:     walletAddress,
    SessionKey: sessionKeyAddress,
})

// Get session keys
keys, err := client.SessionKeysV1GetSessionKeys(ctx, rpc.SessionKeysV1GetSessionKeysRequest{
    Wallet: walletAddress,
})

// Revoke session key
revokeResp, err := client.SessionKeysV1RevokeSessionKey(ctx, rpc.SessionKeysV1RevokeSessionKeyRequest{
    Wallet:     walletAddress,
    SessionKey: sessionKeyToRevoke,
})

Low-Level Usage

Creating Messages Directly
// Create parameters
params, err := rpc.NewPayload(rpc.NodeV1GetAssetsRequest{})
if err != nil {
    return err
}

// Create a request
request := rpc.NewRequest(
    12345,                      // Request ID
    "node.v1.get_assets",       // Method name
    params,                     // Parameters
)

// Send via dialer
response, err := dialer.Call(ctx, &request)
if err != nil {
    return err
}

// Check for errors
if err := response.Error(); err != nil {
    return fmt.Errorf("RPC error: %w", err)
}

// Process response
var result rpc.NodeV1GetAssetsResponse
if err := response.Payload.Translate(&result); err != nil {
    return err
}
Working with Payloads
// Creating payload from a struct
type MyRequest struct {
    Field1 string `json:"field1"`
    Field2 int    `json:"field2"`
}

req := MyRequest{
    Field1: "value",
    Field2: 42,
}

payload, err := rpc.NewPayload(req)
if err != nil {
    return err
}

// Extracting payload into a struct
var received MyRequest
if err := payload.Translate(&received); err != nil {
    return rpc.Errorf("invalid parameters: %v", err)
}
Error Handling
// Check response for errors
response, err := client.NodeV1GetAssets(ctx, req)
if err != nil {
    // This handles both transport errors and RPC errors
    return err
}

// In handlers, use rpc.Errorf for client-facing errors
if amount < 0 {
    return rpc.Errorf("invalid amount: cannot be negative")
}

// Regular errors are treated as internal errors
if err := db.Query(); err != nil {
    return fmt.Errorf("database error: %w", err)
}

Advanced Usage

WebSocket Dialer Configuration
cfg := rpc.WebsocketDialerConfig{
    // Duration to wait for WebSocket handshake (default: 5s)
    HandshakeTimeout: 5 * time.Second,

    // How often to send ping messages (default: 5s)
    PingInterval: 5 * time.Second,

    // Request ID used for ping messages (default: 100)
    PingRequestID: 100,

    // Buffer size for event channel (default: 100)
    EventChanSize: 100,
}

dialer := rpc.NewWebsocketDialer(cfg)
Concurrent RPC Calls
// The client supports concurrent calls from multiple goroutines
var wg sync.WaitGroup

for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()

        ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
        defer cancel()

        err := client.NodeV1Ping(ctx)
        if err != nil {
            log.Error("Ping failed", "id", id, "error", err)
            return
        }

        log.Info("Ping succeeded", "id", id)
    }(i)
}

wg.Wait()

Security Considerations

When using this protocol:

  1. Timestamp Validation: Validate timestamps to prevent replay attacks
  2. Parameter Validation: Thoroughly validate all parameters
  3. Error Messages: Use rpc.Errorf() for safe client-facing errors
  4. Request IDs: Use unique request IDs to prevent duplicate processing
  5. Rate Limiting: Implement rate limiting middleware

Testing

The package includes comprehensive tests:

# Run all tests
go test ./pkg/rpc

# Run with race detector
go test -race ./pkg/rpc

# Run with verbose output
go test -v ./pkg/rpc

Test coverage includes:

  • Message encoding/decoding
  • Payload handling
  • WebSocket dialer functionality
  • All V1 client methods
  • Context and middleware
  • Error handling

Dependencies

  • Standard library: encoding/json, errors, fmt, time, context, sync
  • WebSocket: github.com/gorilla/websocket
  • UUID: github.com/google/uuid

See Also

  • API Documentation - OpenAPI specification for V1 API
  • Package documentation: go doc github.com/layer-3/nitrolite/pkg/rpc

Documentation

Overview

Package rpc provides the RPC API types for the Nitrolite Node service.

This file implements the API request and response definitions specified in api.yaml with versioned types organized by functional groups. All types follow the naming convention: {Group}{Version}{Name}{Request|Response}.

Package rpc provides a high-level client for interacting with the Nitrolite Node RPC server.

This file implements the V1 API client with versioned request/response types following the api.yaml specification.

Package rpc provides the core data structures and utilities for the Nitrolite Node RPC protocol.

This package implements a secure RPC communication protocol designed for blockchain and distributed systems. It provides strong typing, efficient encoding, and clear error handling with versioned API endpoints.

Protocol Overview

The protocol uses a request-response pattern with compact JSON encoding:

  • Messages use typed communication (request, response, event, error response)
  • All messages include timestamps for replay protection
  • Methods follow versioned naming: {group}.v{version}.{action}
  • Responses preserve the request method for easy correlation

Core Types

Messages are the fundamental unit of communication:

type Message struct {
    Type      MsgType // Message type: Req, Resp, Event, or RespErr
    RequestID uint64  // Unique request identifier
    Method    string  // RPC method name (e.g., "node.v1.ping")
    Payload   Payload // Method parameters or response data
    Timestamp uint64  // Unix milliseconds timestamp
}

Message types:

MsgTypeReq     = 1  // Request message
MsgTypeResp    = 2  // Success response message
MsgTypeEvent   = 3  // Server-initiated event notification
MsgTypeRespErr = 4  // Error response message

JSON Encoding

Messages use a compact array encoding for efficiency. A message like:

Message{
    Type:      MsgTypeReq,
    RequestID: 12345,
    Method:    "node.v1.get_config",
    Payload:   {},
    Timestamp: 1634567890123,
}

Encodes to:

[1, 12345, "node.v1.get_config", {}, 1634567890123]

This format reduces message size while maintaining readability and compatibility.

API Versioning

All RPC methods follow a versioned naming convention:

{group}.v{version}.{action}

Examples:

node.v1.ping              // Node group, version 1, ping action
channels.v1.get_channels  // Channels group, version 1, get channels action
user.v1.get_balances      // User group, version 1, get balances action

API groups:

  • node: Node configuration and connectivity
  • channels: Payment channel management and state
  • app_sessions: Application session operations
  • session_keys: Session key management
  • user: User balances and transactions

Error Handling

Error responses use MsgTypeRespErr and preserve the original request method:

// Success response
Message{Type: MsgTypeResp, Method: "node.v1.ping", ...}

// Error response
Message{Type: MsgTypeRespErr, Method: "node.v1.ping", Payload: {"error": "..."}}

Creating error responses:

// In a handler
if err := validate(request); err != nil {
    return NewErrorResponse(request.RequestID, request.Method, err.Error())
}

Checking for errors in responses:

response, err := client.Call(ctx, &request)
if err != nil {
    return err
}
if err := response.Error(); err != nil {
    // Handle RPC error
    return fmt.Errorf("RPC error: %w", err)
}

The package provides explicit error types for client communication:

// Client-facing error - will be sent in response
if amount < 0 {
    return rpc.Errorf("invalid amount: cannot be negative")
}

// Internal error - generic message sent to client
if err := db.Save(); err != nil {
    return fmt.Errorf("database error: %w", err)
}

Parameter Handling

The Payload type provides flexible parameter handling with type safety:

// Creating payload from a struct
payload, err := rpc.NewPayload(NodeV1GetAssetsRequest{
    ChainID: &chainID,
})

// Extracting payload into a struct
var resp NodeV1GetConfigResponse
err := response.Payload.Translate(&resp)

Client Communication

The Client type provides convenient methods for all V1 RPC operations:

// Create client with WebSocket dialer
dialer := rpc.NewWebsocketDialer(rpc.DefaultWebsocketDialerConfig)
client := rpc.NewClient(dialer)

// Connect to server
err := client.Start(ctx, "wss://clearnode-sandbox.yellow.org/v1/ws", func(err error) {
    if err != nil {
        log.Error("Connection closed", "error", err)
    }
})
if err != nil {
    log.Fatal("Failed to start client", "error", err)
}

// Make RPC calls - Node methods
err = client.NodeV1Ping(ctx)
if err != nil {
    log.Error("Ping failed", "error", err)
}

config, err := client.NodeV1GetConfig(ctx)
if err != nil {
    log.Fatal(err)
}
log.Info("Connected to node", "address", config.NodeAddress)

// User methods
balances, err := client.UserV1GetBalances(ctx, rpc.UserV1GetBalancesRequest{
    Wallet: walletAddress,
})
if err != nil {
    log.Fatal(err)
}
for _, balance := range balances.Balances {
    log.Info("Balance", "asset", balance.Asset, "amount", balance.Amount)
}

// Channel methods
channels, err := client.ChannelsV1GetChannels(ctx, rpc.ChannelsV1GetChannelsRequest{
    Wallet: walletAddress,
})
if err != nil {
    log.Fatal(err)
}

## Low-Level Dialer

For direct RPC communication without the convenience methods:

params, _ := rpc.NewPayload(map[string]string{"key": "value"})
request := rpc.NewRequest(12345, "node.v1.ping", params)

response, err := dialer.Call(ctx, &request)
if err != nil {
    log.Error("RPC call failed", "error", err)
}

// Handle events manually
go func() {
    for event := range dialer.EventCh() {
        if event == nil {
            break
        }
        log.Info("Received event", "method", event.Method)
    }
}()

API Types

The package includes comprehensive type definitions for the Nitrolite Node V1 RPC API:

Request/Response Types (organized by group):

  • Node: NodeV1PingRequest/Response, NodeV1GetConfigRequest/Response, etc.
  • Channels: ChannelsV1GetHomeChannelRequest/Response, etc.
  • AppSessions: AppSessionsV1CreateAppSessionRequest/Response, etc.
  • SessionKeys: SessionKeysV1RegisterRequest/Response, etc.
  • User: UserV1GetBalancesRequest/Response, etc.

Common Types:

  • ChannelV1: On-chain channel information
  • StateV1: Channel state with transitions and ledgers
  • TransactionV1: Transaction records
  • AssetV1: Supported asset information
  • BlockchainInfoV1: Supported network information

All types follow the naming convention: {Group}V{Version}{Name}{Request|Response}

Server Implementation

The package provides a complete RPC server implementation through the WebsocketNode:

// Create and configure the server
config := rpc.WebsocketNodeConfig{
    Logger: logger,
}

node, err := rpc.NewWebsocketNode(config)
if err != nil {
    log.Fatal(err)
}

// Register handlers (built-in handlers are registered automatically)
// The node.v1.ping handler is registered by default

node.Handle("user.v1.get_balances", handleGetBalances)
node.Handle("channels.v1.get_channels", handleGetChannels)

// Add middleware
node.Use(loggingMiddleware)
node.Use(authMiddleware)

// Create handler groups
privateGroup := node.NewGroup("private")
privateGroup.Use(requireAuthMiddleware)
privateGroup.Handle("channels.v1.request_creation", handleCreateChannel)

// Start the server
http.Handle("/ws", node)
http.ListenAndServe(":8080", nil)

Writing handlers:

func handleGetBalances(c *rpc.Context) {
    // Extract parameters
    var req UserV1GetBalancesRequest
    if err := c.Request.Payload.Translate(&req); err != nil {
        c.Fail(nil, "invalid parameters")
        return
    }

    // Process request
    balances := getBalancesForWallet(req.Wallet)

    // Create response
    resp := UserV1GetBalancesResponse{
        Balances: balances,
    }
    respPayload, _ := rpc.NewPayload(resp)

    // Send response
    c.Succeed("user.v1.get_balances", respPayload)
}

Writing middleware:

func authMiddleware(c *rpc.Context) {
    // Check if connection is authenticated
    if c.UserID == "" {
        // Try to authenticate from request
        token := extractToken(c.Request)
        userID, err := validateToken(token)
        if err != nil {
            c.Fail(nil, "authentication required")
            return
        }
        c.UserID = userID
    }

    // Continue to next handler
    c.Next()
}

Security Considerations

When using this protocol:

  1. Always validate timestamps to prevent replay attacks
  2. Use rpc.Errorf() for safe client-facing errors
  3. Thoroughly validate all parameters
  4. Use unique request IDs to prevent duplicate processing
  5. Implement proper authentication middleware
  6. Rate limit requests to prevent abuse

Example Usage

Creating and sending a request:

// Create request
params, _ := rpc.NewPayload(NodeV1GetAssetsRequest{})
request := rpc.NewRequest(12345, "node.v1.get_assets", params)

// Marshal and send
data, _ := json.Marshal(request)
// ... send data over WebSocket ...

Processing a request:

// Unmarshal request
var request rpc.Message
err := json.Unmarshal(data, &request)

// Check message type
if request.Type != rpc.MsgTypeReq {
    return rpc.NewErrorResponse(request.RequestID, request.Method, "invalid message type")
}

// Process based on method
switch request.Method {
case "node.v1.ping":
    return rpc.NewResponse(request.RequestID, "node.v1.ping", rpc.Payload{})
case "user.v1.get_balances":
    var params UserV1GetBalancesRequest
    if err := request.Payload.Translate(&params); err != nil {
        return rpc.NewErrorResponse(request.RequestID, request.Method, "invalid parameters")
    }
    // ... handle get balances ...
}

Testing

The package includes a comprehensive test suite:

  • client_test.go: Unit tests for all V1 client methods
  • dialer_test.go: Tests for WebSocket dialer functionality
  • message_test.go: Tests for message encoding/decoding
  • payload_test.go: Tests for payload handling

Run tests with:

go test github.com/layer-3/nitrolite/pkg/rpc

Package rpc provides common method and event type definitions.

Package rpc provides the RPC API types for the Nitrolite Node service.

This file contains common types and structs shared across V1 API groups.

Index

Constants

View Source
const (
	// Channels Group - V1 Methods
	ChannelV1Group                        Group  = "channels.v1"
	ChannelsV1GetHomeChannelMethod        Method = "channels.v1.get_home_channel"
	ChannelsV1GetEscrowChannelMethod      Method = "channels.v1.get_escrow_channel"
	ChannelsV1GetChannelsMethod           Method = "channels.v1.get_channels"
	ChannelsV1GetLatestStateMethod        Method = "channels.v1.get_latest_state"
	ChannelsV1GetStatesMethod             Method = "channels.v1.get_states"
	ChannelsV1RequestCreationMethod       Method = "channels.v1.request_creation"
	ChannelsV1SubmitStateMethod           Method = "channels.v1.submit_state"
	ChannelsV1SubmitSessionKeyStateMethod Method = "channels.v1.submit_session_key_state"
	ChannelsV1GetLastKeyStatesMethod      Method = "channels.v1.get_last_key_states"

	// App Sessions Group - V1 Methods
	AppSessionsV1Group                       Group  = "app_sessions.v1"
	AppSessionsV1SubmitDepositStateMethod    Method = "app_sessions.v1.submit_deposit_state"
	AppSessionsV1SubmitAppStateMethod        Method = "app_sessions.v1.submit_app_state"
	AppSessionsV1RebalanceAppSessionsMethod  Method = "app_sessions.v1.rebalance_app_sessions"
	AppSessionsV1GetAppDefinitionMethod      Method = "app_sessions.v1.get_app_definition"
	AppSessionsV1GetAppSessionsMethod        Method = "app_sessions.v1.get_app_sessions"
	AppSessionsV1CreateAppSessionMethod      Method = "app_sessions.v1.create_app_session"
	AppSessionsV1SubmitSessionKeyStateMethod Method = "app_sessions.v1.submit_session_key_state"
	AppSessionsV1GetLastKeyStatesMethod      Method = "app_sessions.v1.get_last_key_states"

	// Apps Group - V1 Methods
	AppsV1Group                  Group  = "apps.v1"
	AppsV1GetAppsMethod          Method = "apps.v1.get_apps"
	AppsV1SubmitAppVersionMethod Method = "apps.v1.submit_app_version"

	// User Group - V1 Methods
	UserV1Group                     Group  = "user.v1"
	UserV1GetBalancesMethod         Method = "user.v1.get_balances"
	UserV1GetTransactionsMethod     Method = "user.v1.get_transactions"
	UserV1GetActionAllowancesMethod Method = "user.v1.get_action_allowances"

	// Node Group - V1 Methods
	NodeV1Group           Group  = "node.v1"
	NodeV1PingMethod      Method = "node.v1.ping"
	NodeV1GetConfigMethod Method = "node.v1.get_config"
	NodeV1GetAssetsMethod Method = "node.v1.get_assets"
)

Variables

View Source
var (
	// Connection errors
	ErrAlreadyConnected  = fmt.Errorf("already connected")
	ErrNotConnected      = fmt.Errorf("not connected to server")
	ErrConnectionTimeout = fmt.Errorf("websocket connection timeout")
	ErrReadingMessage    = fmt.Errorf("error reading message")

	// Request/Response errors
	ErrNilRequest           = fmt.Errorf("nil request")
	ErrInvalidRequestMethod = fmt.Errorf("invalid request method")
	ErrMarshalingRequest    = fmt.Errorf("error marshaling request")
	ErrSendingRequest       = fmt.Errorf("error sending request")
	ErrNoResponse           = fmt.Errorf("no response received")
	ErrSendingPing          = fmt.Errorf("error sending ping")

	// WebSocket-specific errors
	ErrDialingWebsocket = fmt.Errorf("error dialing websocket server")
)

Dialer error messages

View Source
var DefaultWebsocketDialerConfig = WebsocketDialerConfig{
	HandshakeTimeout: 5 * time.Second,
	PingTimeout:      15 * time.Second,
	EventChanSize:    100,
}

DefaultWebsocketDialerConfig provides sensible defaults for WebSocket connections

Functions

This section is empty.

Types

type ActionAllowanceV1

type ActionAllowanceV1 struct {
	// GatedAction is the specific action being gated (e.g. transfer, app_operation)
	GatedAction core.GatedAction `json:"gated_action"`
	// TimeWindow is the time window for which the allowance is valid (e.g. "1h", "24h")
	TimeWindow string `json:"time_window"`
	// Allowance is the total allowance for the gated action within the time window
	Allowance string `json:"allowance"`
	// Used is the amount of the allowance that has already been used within the time window
	Used string `json:"used"`
}

ActionAllowanceV1 represents the allowance information for a specific gated action.

type AppAllocationV1

type AppAllocationV1 struct {
	// Participant is the participant's wallet address
	Participant string `json:"participant"`
	// Asset is the asset symbol
	Asset string `json:"asset"`
	// Amount is the amount allocated to the participant
	Amount string `json:"amount"`
}

AppAllocationV1 represents the allocation of assets to a participant in an app session.

type AppDefinitionV1

type AppDefinitionV1 struct {
	// Application is the application identifier from an app registry
	Application string `json:"application_id"`
	// Participants is the list of participants in the app session
	Participants []AppParticipantV1 `json:"participants"`
	// Quorum is the quorum required for the app session
	Quorum uint8 `json:"quorum"`
	// Nonce is a unique number to prevent replay attacks
	Nonce string `json:"nonce"`
}

AppDefinitionV1 represents the definition for an app session.

type AppInfoV1

type AppInfoV1 struct {
	AppV1
	// CreatedAt is the creation timestamp (unix seconds)
	CreatedAt string `json:"created_at"`
	// UpdatedAt is the last update timestamp (unix seconds)
	UpdatedAt string `json:"updated_at"`
}

AppInfoV1 represents full application info including timestamps.

type AppParticipantV1

type AppParticipantV1 struct {
	// WalletAddress is the participant's wallet address
	WalletAddress string `json:"wallet_address"`
	// SignatureWeight is the signature weight for the participant
	SignatureWeight uint8 `json:"signature_weight"`
}

AppParticipantV1 represents the definition for an app participant.

type AppSessionInfoV1

type AppSessionInfoV1 struct {
	// AppSessionID is the unique application session identifier
	AppSessionID string `json:"app_session_id"`
	// Status is the session status (open/closed)
	Status string `json:"status"`
	// AppDefinitionV1 contains immutable application fields
	AppDefinitionV1 AppDefinitionV1 `json:"app_definition"`
	// SessionData is the JSON stringified session data
	SessionData *string `json:"session_data,omitempty"`
	// Version is the current version of the session state
	Version string `json:"version"`
	// Nonce is the nonce for the session
	Allocations []AppAllocationV1 `json:"allocations"`
}

AppSessionInfoV1 represents information about an application session.

type AppSessionKeyStateV1

type AppSessionKeyStateV1 struct {
	// ID Hash(user_address + session_key + version)
	// UserAddress is the user wallet address
	UserAddress string `json:"user_address"`
	// SessionKey is the session key address for delegation
	SessionKey string `json:"session_key"`
	// Version is the version of the session key format
	Version string `json:"version"`
	// ApplicationID is the application IDs associated with this session key
	ApplicationIDs []string `json:"application_ids"`
	// AppSessionID is the application session IDs associated with this session key
	AppSessionIDs []string `json:"app_session_ids"`
	// ExpiresAt is Unix timestamp in seconds indicating when the session key expires
	ExpiresAt string `json:"expires_at"`
	// UserSig is the user's signature over the session key metadata to authorize the registration/update of the session key
	UserSig string `json:"user_sig"`
}

AppSessionKeyStateV1 represents the state of a session key.

type AppSessionsV1CreateAppSessionRequest

type AppSessionsV1CreateAppSessionRequest struct {
	// Definition is the application definition including participants and quorum
	Definition AppDefinitionV1 `json:"definition"`
	// SessionData is the optional JSON stringified session data
	SessionData string `json:"session_data"`
	// QuorumSigs is the list of participant signatures for the app session creation
	QuorumSigs []string `json:"quorum_sigs,omitempty"`
	// OwnerSig is the optional owner signature for app session creation if approval required by the app registry
	OwnerSig string `json:"owner_sig,omitempty"`
}

AppSessionsV1CreateAppSessionRequest creates a new application session between participants.

type AppSessionsV1CreateAppSessionResponse

type AppSessionsV1CreateAppSessionResponse struct {
	// AppSessionID is the created application session ID
	AppSessionID string `json:"app_session_id"`
	// Version is the initial version of the session
	Version string `json:"version"`
	// Status is the status of the session (closed)
	Status string `json:"status"`
}

AppSessionsV1CreateAppSessionResponse returns the created application session information.

type AppSessionsV1GetAppDefinitionRequest

type AppSessionsV1GetAppDefinitionRequest struct {
	// AppSessionID is the application session ID
	AppSessionID string `json:"app_session_id"`
}

AppSessionsV1GetAppDefinitionRequest retrieves the application definition for a specific app session.

type AppSessionsV1GetAppDefinitionResponse

type AppSessionsV1GetAppDefinitionResponse struct {
	// Definition is the application definition
	Definition AppDefinitionV1 `json:"definition"`
}

AppSessionsV1GetAppDefinitionResponse returns the application definition.

type AppSessionsV1GetAppSessionsRequest

type AppSessionsV1GetAppSessionsRequest struct {
	// AppSessionID filters by application session ID
	AppSessionID *string `json:"app_session_id,omitempty"`
	// Participant filters by participant wallet address
	Participant *string `json:"participant,omitempty"`
	// Status filters by status (open/closed)
	Status *string `json:"status,omitempty"`
	// Pagination contains pagination parameters (offset, limit, sort)
	Pagination *PaginationParamsV1 `json:"pagination,omitempty"`
}

AppSessionsV1GetAppSessionsRequest lists all application sessions for a participant with optional filtering.

type AppSessionsV1GetAppSessionsResponse

type AppSessionsV1GetAppSessionsResponse struct {
	// AppSessions is the list of application sessions
	AppSessions []AppSessionInfoV1 `json:"app_sessions"`
	// Metadata contains pagination information
	Metadata PaginationMetadataV1 `json:"metadata"`
}

AppSessionsV1GetAppSessionsResponse returns the list of application sessions.

type AppSessionsV1GetLastKeyStatesRequest

type AppSessionsV1GetLastKeyStatesRequest struct {
	// UserAddress is the user's wallet address
	UserAddress string  `json:"user_address"`
	SessionKey  *string `json:"session_key,omitempty"` // Optionally filter by SessionKey
}

AppSessionsV1GetLastKeyStatesRequest retrieves the latest session key states for a user with optional filtering by session key.

type AppSessionsV1GetLastKeyStatesResponse

type AppSessionsV1GetLastKeyStatesResponse struct {
	// States is the list of active session key states for the user
	States []AppSessionKeyStateV1 `json:"states"`
}

SessionKeysV1GetSessionKeysResponse returns the list of active session keys.

type AppSessionsV1RebalanceAppSessionsRequest

type AppSessionsV1RebalanceAppSessionsRequest struct {
	// SignedUpdates is the list of signed application session state updates
	SignedUpdates []SignedAppStateUpdateV1 `json:"signed_updates"`
}

AppSessionsV1RebalanceAppSessionsRequest rebalances multiple application sessions atomically.

type AppSessionsV1RebalanceAppSessionsResponse

type AppSessionsV1RebalanceAppSessionsResponse struct {
	// BatchID is the unique identifier for this rebalancing operation
	BatchID string `json:"batch_id"`
}

AppSessionsV1RebalanceAppSessionsResponse returns the batch ID for the rebalancing operation.

type AppSessionsV1SubmitAppStateRequest

type AppSessionsV1SubmitAppStateRequest struct {
	// AppStateUpdate is the application session state update to be submitted
	AppStateUpdate AppStateUpdateV1 `json:"app_state_update"`
	// QuorumSigs is the signature quorum for the application session
	QuorumSigs []string `json:"quorum_sigs"`
}

AppSessionsV1SubmitAppStateRequest submits an application session state update.

type AppSessionsV1SubmitAppStateResponse

type AppSessionsV1SubmitAppStateResponse struct{}

AppSessionsV1SubmitAppStateResponse returns the Node's signature for the new User state.

type AppSessionsV1SubmitDepositStateRequest

type AppSessionsV1SubmitDepositStateRequest struct {
	// AppStateUpdate is the application session state update to be submitted
	AppStateUpdate AppStateUpdateV1 `json:"app_state_update"`
	// QuorumSigs is the list of participant signatures for the app state update
	QuorumSigs []string `json:"quorum_sigs"`
	// SigQuorum is the signature quorum for the application session
	UserState StateV1 `json:"user_state"`
}

AppSessionsV1SubmitDepositStateRequest submits an application session state update.

type AppSessionsV1SubmitDepositStateResponse

type AppSessionsV1SubmitDepositStateResponse struct {
	// StateNodeSig is the Node's signature for the deposit state
	StateNodeSig string `json:"signature"`
}

AppSessionsV1SubmitDepositStateResponse returns the Node's signature for the deposit state.

type AppSessionsV1SubmitSessionKeyStateRequest

type AppSessionsV1SubmitSessionKeyStateRequest struct {
	// State contains the session key metadata and delegation information
	State AppSessionKeyStateV1 `json:"state"`
}

AppSessionsV1SubmitSessionKeyStateRequest submits the session key state for registration and updates.

type AppSessionsV1SubmitSessionKeyStateResponse

type AppSessionsV1SubmitSessionKeyStateResponse struct {
}

AppSessionsV1SubmitSessionKeyStateResponse returns the result of session key state submission.

type AppStateUpdateV1

type AppStateUpdateV1 struct {
	// AppSessionID is the unique application session identifier
	AppSessionID string `json:"app_session_id"`
	// Intent is the intent of the app session update (operate, deposit, withdraw, close)
	Intent app.AppStateUpdateIntent `json:"intent"`
	// Version is the version of the app state
	Version string `json:"version"`
	// Allocations is the list of allocations in the app state
	Allocations []AppAllocationV1 `json:"allocations"`
	// SessionData is the JSON stringified session data
	SessionData string `json:"session_data"`
}

AppStateUpdateV1 represents the current state of an application session.

type AppV1

type AppV1 struct {
	// ID is the application identifier
	ID string `json:"id"`
	// OwnerWallet is the owner's wallet address
	OwnerWallet string `json:"owner_wallet"`
	// Metadata is the application metadata
	Metadata string `json:"metadata"`
	// Version is the current version
	Version string `json:"version"`
	// CreationApprovalNotRequired indicates if sessions can be created without approval
	CreationApprovalNotRequired bool `json:"creation_approval_not_required"`
}

AppV1 represents a registered application definition (without timestamps).

type AppsV1GetAppsRequest

type AppsV1GetAppsRequest struct {
	// AppID filters by application ID
	AppID *string `json:"app_id,omitempty"`
	// OwnerWallet filters by owner wallet address
	OwnerWallet *string `json:"owner_wallet,omitempty"`
	// Pagination contains pagination parameters (offset, limit, sort)
	Pagination *PaginationParamsV1 `json:"pagination,omitempty"`
}

AppsV1GetAppsRequest retrieves registered applications with optional filtering.

type AppsV1GetAppsResponse

type AppsV1GetAppsResponse struct {
	// Apps is the list of registered applications
	Apps []AppInfoV1 `json:"apps"`
	// Metadata contains pagination information
	Metadata PaginationMetadataV1 `json:"metadata"`
}

AppsV1GetAppsResponse returns the list of registered applications.

type AppsV1SubmitAppVersionRequest

type AppsV1SubmitAppVersionRequest struct {
	// App contains the application definition
	App AppV1 `json:"app"`
	// OwnerSig is the owner's signature over the packed app data
	OwnerSig string `json:"owner_sig"`
}

AppsV1SubmitAppVersionRequest submits a new application version (currently only creation is supported).

type AppsV1SubmitAppVersionResponse

type AppsV1SubmitAppVersionResponse struct {
}

AppsV1SubmitAppVersionResponse returns the result of the application version submission.

type AssetV1

type AssetV1 struct {
	// Name is the asset name
	Name string `json:"name"`
	// Symbol is the asset symbol
	Symbol string `json:"symbol"`
	// Decimals is the number of decimal places for the asset
	Decimals uint8 `json:"decimals"`
	// SuggestedBlockchainID is the suggested blockchain network ID for this asset
	SuggestedBlockchainID string `json:"suggested_blockchain_id"`
	// Tokens is the list of supported tokens for the asset
	Tokens []TokenV1 `json:"tokens"`
}

AssetV1 represents information about a supported asset.

type BalanceEntryV1

type BalanceEntryV1 struct {
	// Asset is the asset symbol
	Asset string `json:"asset"`
	// Amount is the balance amount
	Amount string `json:"amount"`
}

BalanceEntryV1 represents a balance for a specific asset.

type BlockchainInfoV1

type BlockchainInfoV1 struct {
	// Name is the blockchain name
	Name string `json:"name"`
	// BlockchainID is the blockchain network ID
	BlockchainID string `json:"blockchain_id"`
	// ChannelHubAddress is the contract address on this network
	ChannelHubAddress string `json:"channel_hub_address"`
	// LockingContractAddress is the contract address for the locking contract on this network
	LockingContractAddress string `json:"locking_contract_address"`
}

BlockchainInfoV1 represents information about a supported network.

type ChannelDefinitionV1

type ChannelDefinitionV1 struct {
	// Nonce is a unique number to prevent replay attacks
	Nonce string `json:"nonce"`
	// Challenge is the challenge period for the channel in seconds
	Challenge uint32 `json:"challenge"`
	// ApprovedSigValidators is a hex string bitmap representing the approved signature validators for the channel
	ApprovedSigValidators string `json:"approved_sig_validators"`
}

ChannelDefinitionV1 represents the configuration for creating a channel.

type ChannelSessionKeyStateV1

type ChannelSessionKeyStateV1 struct {
	// ID Hash(user_address + session_key + version)
	// UserAddress is the user wallet address
	UserAddress string `json:"user_address"`
	// SessionKey is the session key address for delegation
	SessionKey string `json:"session_key"`
	// Version is the version of the session key format
	Version string `json:"version"`
	// Assets associated with this session key
	Assets []string `json:"assets"`
	// Expiration time as unix timestamp of this session key
	ExpiresAt string `json:"expires_at"`
	// UserSig is the user's signature over the session key metadata to authorize the registration/update of the session key
	UserSig string `json:"user_sig"`
}

ChannelSessionKeyStateV1 represents the state of a session key.

type ChannelV1

type ChannelV1 struct {
	// ChannelID is the unique identifier for the channel
	ChannelID string `json:"channel_id"`
	// UserWallet is the user wallet address
	UserWallet string `json:"user_wallet"`
	// Asset is the asset symbol (e.g. USDC, ETH)
	Asset string `json:"asset"`
	// Type is the type of the channel (home, escrow)
	Type string `json:"type"`
	// BlockchainID is the unique identifier for the blockchain
	BlockchainID string `json:"blockchain_id"`
	// TokenAddress is the address of the token used in the channel
	TokenAddress string `json:"token_address"`
	// ChallengeDuration is the challenge period for the channel in seconds
	ChallengeDuration uint32 `json:"challenge_duration"`
	// ChallegeExpiresAt
	ChallengeExpiresAt *time.Time `json:"challenge_expires_at"`
	// Nonce is the nonce for the channel
	Nonce string `json:"nonce"`
	// ApprovedSigValidators is a hex string bitmap of approved signature validators
	ApprovedSigValidators string `json:"approved_sig_validators"`
	// Status is the current status of the channel (void, open, challenged, closed)
	Status string `json:"status"`
	// StateVersion is the on-chain state version of the channel
	StateVersion string `json:"state_version"`
}

ChannelV1 represents an on-chain channel.

type ChannelsV1GetChannelsRequest

type ChannelsV1GetChannelsRequest struct {
	// Wallet filters by user's wallet address
	Wallet string `json:"wallet"`
	// Status filters by status
	Status *string `json:"status,omitempty"`
	// Asset filters by asset
	Asset *string `json:"asset,omitempty"`
	// ChannelType filters by channel type ("home" or "escrow")
	ChannelType *string `json:"channel_type,omitempty"`
	// Pagination contains pagination parameters (offset, limit, sort)
	Pagination *PaginationParamsV1 `json:"pagination,omitempty"`
}

ChannelsV1GetChannelsRequest retrieves all channels for a user with optional filtering.

type ChannelsV1GetChannelsResponse

type ChannelsV1GetChannelsResponse struct {
	// Channels is the list of channels
	Channels []ChannelV1 `json:"channels"`
	// Metadata contains pagination information
	Metadata PaginationMetadataV1 `json:"metadata"`
}

ChannelsV1GetChannelsResponse returns the list of channels.

type ChannelsV1GetEscrowChannelRequest

type ChannelsV1GetEscrowChannelRequest struct {
	// EscrowChannelID is the escrow channel ID
	EscrowChannelID string `json:"escrow_channel_id"`
}

ChannelsV1GetEscrowChannelRequest retrieves current on-chain escrow channel information.

type ChannelsV1GetEscrowChannelResponse

type ChannelsV1GetEscrowChannelResponse struct {
	// Channel is the on-chain channel information
	Channel ChannelV1 `json:"channel"`
}

ChannelsV1GetEscrowChannelResponse returns the on-chain channel information.

type ChannelsV1GetHomeChannelRequest

type ChannelsV1GetHomeChannelRequest struct {
	// UserWallet is the user's wallet address
	Wallet string `json:"wallet"`
	// Asset is the asset symbol
	Asset string `json:"asset"`
}

ChannelsV1GetHomeChannelRequest retrieves current on-chain home channel information.

type ChannelsV1GetHomeChannelResponse

type ChannelsV1GetHomeChannelResponse struct {
	// Channel is the on-chain channel information
	Channel ChannelV1 `json:"channel"`
}

ChannelsV1GetHomeChannelResponse returns the on-chain channel information.

type ChannelsV1GetLastKeyStatesRequest

type ChannelsV1GetLastKeyStatesRequest struct {
	// UserAddress is the user's wallet address
	UserAddress string  `json:"user_address"`
	SessionKey  *string `json:"session_key,omitempty"` // Optionally filter by SessionKey
}

ChannelsV1GetLastKeyStatesRequest retrieves the latest session key states for a user with optional filtering by session key.

type ChannelsV1GetLastKeyStatesResponse

type ChannelsV1GetLastKeyStatesResponse struct {
	// States is the list of active session key states for the user
	States []ChannelSessionKeyStateV1 `json:"states"`
}

ChannelsV1GetSessionKeysResponse returns the list of active session keys.

type ChannelsV1GetLatestStateRequest

type ChannelsV1GetLatestStateRequest struct {
	// UserWallet is the user's wallet address
	Wallet string `json:"wallet"`
	// Asset is the asset symbol
	Asset string `json:"asset"`
	// OnlySigned can be enabled to get the latest signed state to know what is the current pending transition
	OnlySigned bool `json:"only_signed"`
}

ChannelsV1GetLatestStateRequest retrieves the current state of the user stored on the Node.

type ChannelsV1GetLatestStateResponse

type ChannelsV1GetLatestStateResponse struct {
	// State is the current state of the user
	State StateV1 `json:"state"`
}

ChannelsV1GetLatestStateResponse returns the current state of the user.

type ChannelsV1GetStatesRequest

type ChannelsV1GetStatesRequest struct {
	// Wallet is the user's wallet address
	Wallet string `json:"wallet"`
	// Asset filters by asset symbol
	Asset string `json:"asset"`
	// Epoch filters by user epoch index
	Epoch *string `json:"epoch,omitempty"`
	// ChannelID filters by Home/Escrow Channel ID
	ChannelID *string `json:"channel_id,omitempty"`
	// OnlySigned returns only signed states
	OnlySigned bool `json:"only_signed"`
	// Pagination contains pagination parameters (offset, limit, sort)
	Pagination *PaginationParamsV1 `json:"pagination,omitempty"`
}

ChannelsV1GetStatesRequest retrieves state history for a user with optional filtering.

type ChannelsV1GetStatesResponse

type ChannelsV1GetStatesResponse struct {
	// States is the list of states
	States []StateV1 `json:"states"`
	// Metadata contains pagination information
	Metadata PaginationMetadataV1 `json:"metadata"`
}

ChannelsV1GetStatesResponse returns the list of states.

type ChannelsV1HomeChannelCreatedEvent

type ChannelsV1HomeChannelCreatedEvent struct {
	// Channel is the created home channel information
	Channel ChannelV1 `json:"channel"`
	// InitialState is the initial state of the home channel
	InitialState StateV1 `json:"initial_state"`
}

ChannelsV1HomeChannelCreatedEvent is emitted when a home channel is created.

type ChannelsV1RequestCreationRequest

type ChannelsV1RequestCreationRequest struct {
	// State is the state to be submitted
	State StateV1 `json:"state"`
	// ChannelDefinition is the definition of the channel to be created
	ChannelDefinition ChannelDefinitionV1 `json:"channel_definition"`
}

ChannelsV1RequestCreationRequest requests the creation of a channel from Node.

type ChannelsV1RequestCreationResponse

type ChannelsV1RequestCreationResponse struct {
	// Signature is the Node's signature for the state
	Signature string `json:"signature"`
}

ChannelsV1RequestCreationResponse returns the Node's signature for the state.

type ChannelsV1SubmitSessionKeyStateRequest

type ChannelsV1SubmitSessionKeyStateRequest struct {
	// State contains the session key metadata and delegation information
	State ChannelSessionKeyStateV1 `json:"state"`
}

ChannelsV1SubmitSessionKeyStateRequest submits the session key state for registration and updates.

type ChannelsV1SubmitSessionKeyStateResponse

type ChannelsV1SubmitSessionKeyStateResponse struct {
}

ChannelsV1SubmitSessionKeyStateResponse returns the result of session key state submission.

type ChannelsV1SubmitStateRequest

type ChannelsV1SubmitStateRequest struct {
	// State is the state to be submitted
	State StateV1 `json:"state"`
}

ChannelsV1SubmitStateRequest submits a cross-chain state.

type ChannelsV1SubmitStateResponse

type ChannelsV1SubmitStateResponse struct {
	// Signature is the Node's signature for the state
	Signature string `json:"signature"`
}

ChannelsV1SubmitStateResponse returns the Node's signature for the state.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client provides a high-level interface for interacting with the Nitrolite Node V1 RPC API. It wraps a Dialer to provide convenient methods for all V1 RPC operations.

The Client supports:

  • Channel management (home and escrow channels)
  • State queries and submissions
  • Application session operations
  • Session key management
  • User balance and transaction queries
  • Node configuration and asset queries

Example usage:

dialer := rpc.NewWebsocketDialer(rpc.DefaultWebsocketDialerConfig)
client := rpc.NewClient(dialer)

// Connect to the server
err := client.Start(ctx, "wss://clearnode-sandbox.yellow.org/v1/ws", handleError)
if err != nil {
    log.Fatal(err)
}

// Make RPC calls
config, err := client.NodeV1GetConfig(ctx)
if err != nil {
    log.Fatal(err)
}

func NewClient

func NewClient(dialer Dialer) *Client

NewClient creates a new V1 RPC client using the provided dialer. The dialer must be connected before making RPC calls.

func (*Client) AppSessionsV1CreateAppSession

AppSessionsV1CreateAppSession creates a new application session between participants.

func (*Client) AppSessionsV1GetAppDefinition

AppSessionsV1GetAppDefinition retrieves the application definition for a specific app session.

func (*Client) AppSessionsV1GetAppSessions

AppSessionsV1GetAppSessions lists all application sessions for a participant with optional filtering.

func (*Client) AppSessionsV1GetLastKeyStates

AppSessionsV1GetSessionKeys retrieves all active session keys for the authenticated user.

func (*Client) AppSessionsV1RebalanceAppSessions

AppSessionsV1RebalanceAppSessions rebalances multiple application sessions atomically.

func (*Client) AppSessionsV1SubmitAppState

AppSessionsV1SubmitAppState submits an application session state update.

func (*Client) AppSessionsV1SubmitDepositState

AppSessionsV1SubmitDepositState submits an application session state update.

func (*Client) AppSessionsV1SubmitSessionKeyState

AppSessionsV1Register initiates session key registration.

func (*Client) AppsV1GetApps

func (c *Client) AppsV1GetApps(ctx context.Context, req AppsV1GetAppsRequest) (AppsV1GetAppsResponse, error)

AppsV1GetApps retrieves registered applications with optional filtering.

func (*Client) AppsV1SubmitAppVersion

AppsV1SubmitAppVersion submits a new application version (currently only creation is supported).

func (*Client) ChannelsV1GetChannels

ChannelsV1GetChannels retrieves all channels for a user with optional filtering.

func (*Client) ChannelsV1GetEscrowChannel

ChannelsV1GetEscrowChannel retrieves current on-chain escrow channel information.

func (*Client) ChannelsV1GetHomeChannel

ChannelsV1GetHomeChannel retrieves current on-chain home channel information.

func (*Client) ChannelsV1GetLastKeyStates

ChannelsV1GetLastKeyStates retrieves the latest channel session key states for a user.

func (*Client) ChannelsV1GetLatestState

ChannelsV1GetLatestState retrieves the current state of the user stored on the Node.

func (*Client) ChannelsV1GetStates

ChannelsV1GetStates retrieves state history for a user with optional filtering.

func (*Client) ChannelsV1RequestCreation

ChannelsV1RequestCreation requests the creation of a channel from Node.

func (*Client) ChannelsV1SubmitSessionKeyState

ChannelsV1SubmitSessionKeyState submits a channel session key state for registration or update.

func (*Client) ChannelsV1SubmitState

ChannelsV1SubmitState submits a cross-chain state.

func (*Client) NodeV1GetAssets

NodeV1GetAssets retrieves all supported assets with optional chain filter.

func (*Client) NodeV1GetConfig

func (c *Client) NodeV1GetConfig(ctx context.Context) (NodeV1GetConfigResponse, error)

NodeV1GetConfig retrieves broker configuration and supported networks.

func (*Client) NodeV1Ping

func (c *Client) NodeV1Ping(ctx context.Context) error

NodeV1Ping sends a ping request to the server to check connectivity.

func (*Client) Start

func (c *Client) Start(ctx context.Context, url string, handleClosure func(err error)) error

Start establishes a connection to the RPC server. This is a convenience method that wraps the dialer's Dial method.

func (*Client) UserV1GetActionAllowances

UserV1GetActionAllowances retrieves the user's current action allowances for channels and app sessions.

func (*Client) UserV1GetBalances

UserV1GetBalances retrieves the balances of the user in YN.

func (*Client) UserV1GetTransactions

UserV1GetTransactions retrieves ledger transaction history with optional filtering.

type Connection

type Connection interface {
	// ConnectionID returns the unique identifier for this connection.
	// This ID is generated when the connection is established and remains
	// constant throughout the connection's lifetime.
	ConnectionID() string

	// Origin returns the origin of the connection, such as the client's IP address or other identifying information.
	Origin() string

	// RawRequests returns a read-only channel for receiving incoming raw request messages.
	// Messages received on this channel are raw bytes that need to be unmarshaled
	// into Request objects for processing. The channel is closed when the
	// connection is terminated.
	RawRequests() <-chan []byte

	// WriteRawResponse attempts to send a raw response message to the client.
	// The method returns true if the message was successfully queued for sending,
	// or false if the operation timed out (indicating a potentially unresponsive client).
	// Messages that fail to send may trigger connection closure.
	WriteRawResponse(message []byte) bool

	// Serve starts the connection's lifecycle by spawning goroutines for reading and writing.
	// This method returns immediately after starting the goroutines. The handleClosure
	// callback will be invoked asynchronously when the connection terminates (with an
	// error if abnormal termination occurred). The parentCtx parameter enables
	// graceful shutdown of the connection.
	Serve(parentCtx context.Context, handleClosure func(error))
}

Connection represents an active RPC connection that handles bidirectional communication. Implementations of this interface manage the connection lifecycle and message routing. The interface is designed to be transport-agnostic, though the primary implementation uses WebSocket.

type ConnectionHub

type ConnectionHub struct {
	// contains filtered or unexported fields
}

ConnectionHub provides centralized management of all active RPC connections. It maintains thread-safe mappings between connection IDs and Connection instances, as well as user IDs and their associated connections. This enables efficient message routing and connection lifecycle management.

Key features:

  • Thread-safe connection storage and retrieval
  • User-to-connection mapping for authenticated sessions
  • Automatic cleanup of auth mappings when connections close
  • Support for re-authentication (updating user associations)
  • Broadcast capabilities to all connections for a specific user

func NewConnectionHub

func NewConnectionHub(observeConnections ObserveConnectionsFn) *ConnectionHub

NewConnectionHub creates a new ConnectionHub instance with initialized maps. The hub is typically used internally by Node implementations to manage the lifecycle of all active connections.

func (*ConnectionHub) Add

func (hub *ConnectionHub) Add(conn Connection) error

Add registers a new connection with the hub. The connection is indexed by its ConnectionID for fast retrieval.

Returns an error if:

  • The connection is nil
  • A connection with the same ID already exists

func (*ConnectionHub) Get

func (hub *ConnectionHub) Get(connID string) Connection

Get retrieves a connection by its unique connection ID. Returns the Connection instance if found, or nil if no connection with the specified ID exists in the hub.

This method is safe for concurrent access.

func (*ConnectionHub) Publish

func (hub *ConnectionHub) Publish(userID string, response []byte)

Publish broadcasts a message to all active connections for a specific user. This enables server-initiated notifications to be sent to all of a user's connected clients (e.g., multiple browser tabs or devices).

The method:

  • Looks up all connections associated with the user
  • Attempts to send the message to each connection
  • Silently skips any connections that fail to accept the message

If the user has no active connections, the message is silently dropped. This method is safe for concurrent access. TODO: refine with subscription topics capability

func (*ConnectionHub) Remove

func (hub *ConnectionHub) Remove(connID string)

Remove unregisters a connection from the hub. This method:

  • Removes the connection from the main connection map
  • Cleans up any user-to-connection mappings
  • Removes empty user entries to prevent memory leaks

If the connection doesn't exist, this method does nothing (no-op). This method is safe for concurrent access.

type Context

type Context struct {
	// Context is the standard Go context for the request
	Context context.Context
	// Request is the original RPC request message
	Request Message
	// Response is the response message to be sent back to the client
	Response Message
	// Storage provides per-connection storage for session data
	Storage *SafeStorage
	// contains filtered or unexported fields
}

Context encapsulates all information related to an RPC request and provides methods for handlers to process and respond. It implements a middleware pattern where handlers can be chained together, each having the ability to process the request, modify the context, or delegate to the next handler.

The Context serves multiple purposes:

  • Request/response container: Holds the incoming request and outgoing response
  • Middleware chain management: Tracks and executes the handler chain
  • Session state: Provides per-connection storage for maintaining state
  • Response helpers: Convenient methods for success and error responses

func (*Context) Fail

func (c *Context) Fail(err error, fallbackMessage string)

Fail sets an error response for the RPC request. This method should be called by handlers when an error occurs during request processing.

Error handling behavior:

  • If err is an RPCError: The exact error message is sent to the client
  • If err is any other error type: The fallbackMessage is sent to the client
  • If both err is nil/non-RPCError AND fallbackMessage is empty: A generic error message is sent

This design allows handlers to control what error information is exposed to clients:

  • Use RPCError for client-safe, descriptive error messages
  • Use regular errors with a fallbackMessage to hide internal error details

Usage examples:

// Hide internal error details from client
balance, err := ledger.GetBalance(account)
if err != nil {
	c.Fail(err, "failed to retrieve balance")
	return
}

// Validation error with no internal error
if len(params) < 3 {
	c.Fail(nil, "invalid parameters: expected at least 3")
	return
}

The response will have Method="error" and Params containing the error message.

func (*Context) Next

func (c *Context) Next()

Next advances the middleware chain by executing the next handler. This enables handlers to perform pre-processing, call Next() to delegate to subsequent handlers, then perform post-processing. If there are no more handlers in the chain, Next() returns immediately without error.

Example middleware pattern:

func invalidRequest(c *Context) {
    // Pre-processing: check request message type
    if c.Request.Type != MsgTypeReq {
        c.Fail(nil, "invalid request")
        return
    }
    c.Next() // Continue to next handler
}

func (*Context) Succeed

func (c *Context) Succeed(method string, payload Payload)

Succeed sets a successful response for the RPC request. This method should be called by handlers when the request has been processed successfully. The method parameter typically matches the request method, and params contains the result data.

Example:

func handleGetBalance(c *Context) {
    balance := getBalanceForUser(c.Request.Payload{"userWallet"})
    c.Succeed("get_balance", Payload{"balance": balance})
}

type Dialer

type Dialer interface {
	// Dial establishes a connection to the specified URL.
	// This method is designed to be called in a goroutine as it blocks until the connection is closed.
	// The handleClosure callback is invoked when the connection is closed, with an error if any.
	Dial(ctx context.Context, url string, handleClosure func(err error)) error

	// IsConnected returns true if the dialer has an active connection.
	IsConnected() bool

	// Call sends an RPC request and waits for a response.
	// It returns an error if the request cannot be sent or no response is received.
	// The context can be used to cancel the request.
	Call(ctx context.Context, req *Message) (*Message, error)

	// EventCh returns a read-only channel for receiving unsolicited events from the server.
	// Events are responses that don't match any pending request ID.
	EventCh() <-chan *Message
}

Dialer is the interface for RPC client connections. It provides methods to establish connections, send requests, and receive responses.

type Error

type Error struct {
	// contains filtered or unexported fields
}

Error represents an error in the RPC protocol that should be sent back to the client in the RPC response. Unlike generic errors, Error messages are guaranteed to be included in the error response sent to the client.

Use Error when you want to provide specific, user-facing error messages in RPC responses. For internal errors that should not be exposed to clients, use regular errors instead.

Example:

// Client will receive this exact error message
return rpc.Errorf("invalid wallet address: %s", addr)

// Client will receive a generic error message
return fmt.Errorf("database connection failed")

func Errorf

func Errorf(format string, args ...any) Error

Errorf creates a new Error with a formatted error message that will be sent to the client in the RPC response. This is the preferred way to create client-facing errors in RPC handlers.

The error message should be clear, actionable, and safe to expose to external clients. Avoid including sensitive information like internal system details, file paths, or database specifics.

Usage in RPC handlers:

// In a handler function that returns an error
if amount.IsNegative() {
	return Errorf("invalid amount: cannot be negative")
}

// With formatting for specific details
if balance.LessThan(amount) {
	return Errorf("insufficient balance: need %s but have %s", amount, balance)
}

func NewError

func NewError(err error) Error

NewError creates a new Error from an existing error. The message from the provided error will be included in the RPC response sent to the client.

Use this function when you have an existing error that contains a user-friendly message that you want to send back to the client. If the original error message is not suitable for client consumption, consider using Errorf to create a new Error with a custom message.

Example:

// Creating an Error from an existing error
if err := validateAddress(addr); err != nil {
    return rpc.NewError(err)
}

// This will send the original error message to the client, so ensure it's appropriate for exposure.

func (Error) Error

func (e Error) Error() string

Error implements the error interface for Error. It returns the underlying error message that will be sent to clients.

This method allows Error to be used anywhere a standard Go error is expected, while maintaining the distinction that this error's message is safe for external client consumption.

type Event

type Event string

Event represents a notification event type sent by the server. Events are unsolicited notifications sent to connected clients.

func (Event) String

func (e Event) String() string

String returns the string representation of the event.

type GorillaWsConnectionAdapter

type GorillaWsConnectionAdapter interface {
	// ReadMessage reads a message from the WebSocket connection.
	ReadMessage() (messageType int, p []byte, err error)
	// NextWriter returns a writer for the next message to be sent on the WebSocket connection.
	NextWriter(messageType int) (io.WriteCloser, error)
	// Close closes the WebSocket connection.
	Close() error
	// WriteControl writes a control message (ping, pong, close) to the connection.
	WriteControl(messageType int, data []byte, deadline time.Time) error
	// SetPongHandler sets the handler for pong messages received from the peer.
	SetPongHandler(h func(appData string) error)
	// SetReadDeadline sets the deadline for future Read calls.
	// A zero value means reads will not time out.
	SetReadDeadline(t time.Time) error
}

GorillaWsConnectionAdapter abstracts the methods of a WebSocket connection needed by WebsocketConnection.

type Group

type Group string

Method represents an RPC method name that can be called on the server.

func (Group) String

func (g Group) String() string

String returns the string representation of the group.

type Handler

type Handler func(c *Context)

Handler defines the function signature for RPC request processors. Handlers receive a Context containing the request and all necessary information to process it. They can call c.Next() to delegate to the next handler in the middleware chain, enabling composable request processing pipelines.

type HandlerGroup

type HandlerGroup interface {
	Handle(method string, handler Handler)
	Use(middleware Handler)
	NewGroup(name string) HandlerGroup
}

type LedgerV1

type LedgerV1 struct {
	// TokenAddress is the address of the token used in this channel
	TokenAddress string `json:"token_address"`
	// BlockchainID is the unique identifier for the blockchain
	BlockchainID string `json:"blockchain_id"`
	// UserBalance is the user balance in the channel
	UserBalance string `json:"user_balance"`
	// UserNetFlow is the user net flow in the channel
	UserNetFlow string `json:"user_net_flow"`
	// NodeBalance is the node balance in the channel
	NodeBalance string `json:"node_balance"`
	// NodeNetFlow is the node net flow in the channel
	NodeNetFlow string `json:"node_net_flow"`
}

LedgerV1 represents ledger balances for a channel.

type Message

type Message struct {
	Type MsgType `json:"type"`

	// RequestID is a unique identifier for tracking requests and matching responses.
	// Clients should generate unique IDs to prevent collisions and enable proper
	// request-response correlation.
	RequestID uint64 `json:"request_id"`

	// Method specifies the RPC method to be invoked (e.g., "wallet_transfer").
	// Method names should follow a consistent naming convention, typically
	// using lowercase with underscores (e.g., "module_action").
	Method string `json:"method"`

	// Payload contains the method-specific parameters as a flexible map.
	// This allows different methods to have different parameter structures
	// while maintaining type safety through the Translate method.
	Payload Payload `json:"payload"`

	// Timestamp is the Unix timestamp in milliseconds when the payload was created.
	// This is used for replay protection and request expiration checks.
	// Servers should validate that timestamps are within an acceptable time window.
	Timestamp uint64 `json:"ts"`
}

Message represents the core data structure for RPC communication. It contains all the information needed to process an RPC call, response, or event.

Messages are encoded as JSON arrays for compact transmission: [Type, RequestID, Method, Params, Timestamp]

This encoding reduces message size while maintaining human readability and allows for efficient parsing. The array format is automatically handled by the custom JSON marshaling methods.

func NewErrorResponse

func NewErrorResponse(requestID uint64, method string, errMsg string) Message

NewErrorResponse creates an error Response message containing an error message. This is a convenience function that combines error parameter creation and response construction in a single call.

The message type is set to MsgTypeRespErr and the method is preserved from the request.

Parameters:

  • requestID: The ID from the original request
  • method: The method from the original request
  • errMsg: The error message to send to the client

Example usage:

// In an RPC handler when an error occurs
if err := validateRequest(request); err != nil {
    return NewErrorResponse(request.RequestID, request.Method, err.Error())
}

// Creating an error response
errorResponse := NewErrorResponse(12345, "node.v1.ping", "insufficient balance")

The resulting response will have type MsgTypeRespErr, the same method as the request, and params in the format: {"error": "<errMsg>"}

func NewEvent

func NewEvent(requestID uint64, method string, params Payload) Message

func NewMessage

func NewMessage(typ MsgType, id uint64, method string, params Payload) Message

NewMessage creates a new Message with the given request ID, type, method, and parameters. The timestamp is automatically set to the current time in Unix milliseconds.

Example:

params, _ := NewParams(map[string]string{"address": "0x123"})
message := NewMessage(MsgTypeReq, 12345, "wallet_getBalance", params)

The resulting message will have the current timestamp and can be used for requests, responses, or events depending on the type specified.

func NewRequest

func NewRequest(requestID uint64, method string, params Payload) Message

NewRequest creates a new Request message with the given request ID, method, and parameters. The message type is automatically set to MsgTypeReq and the timestamp is set to the current time.

Example usage:

// Create a request message
params, _ := NewParams(map[string]string{"address": "0x123"})
request := NewRequest(12345, "wallet_getBalance", params)

// Create a request with complex parameters
type TransferParams struct {
    To     string `json:"to"`
    Amount string `json:"amount"`
}
params, _ := NewParams(TransferParams{To: "0xabc", Amount: "100"})
request := NewRequest(67890, "wallet_transfer", params)

func NewResponse

func NewResponse(requestID uint64, method string, params Payload) Message

NewResponse creates a new Response message with the given request ID, method, and parameters. The message type is automatically set to MsgTypeResp and the timestamp is set to the current time.

Example usage:

// Create a success response
params, _ := NewParams(map[string]string{"balance": "1000"})
response := NewResponse(12345, "wallet_getBalance", params)

func (Message) Error

func (r Message) Error() error

Error checks if the Message contains an error and returns it. This method extracts any error stored in the message's payload under the standard "error" key by checking if the message type is MsgTypeRespErr.

Returns:

  • An error if the message type is MsgTypeRespErr
  • nil if the message represents a successful operation

This is typically used by clients to check if an RPC call failed:

// After receiving and unmarshaling a response message
var message Message
if err := json.Unmarshal(data, &message); err != nil {
    return fmt.Errorf("failed to unmarshal message: %w", err)
}

// Check if the message contains an error
if err := message.Error(); err != nil {
    return fmt.Errorf("RPC call failed: %w", err)
}

// Process successful response
var result TransferResult
message.Payload.Translate(&result)

This method is designed to work with error responses created by NewErrorResponse or any response where errors are stored using NewErrorParams.

func (Message) MarshalJSON

func (p Message) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface for Message. It always emits the compact array format: [Type, RequestID, Method, Params, Timestamp]

This ensures consistent wire format regardless of how the Message struct is modified in the future, maintaining protocol compatibility.

Example output:

[1, 12345, "wallet_transfer", {"to": "0xabc", "amount": "100"}, 1634567890123]

func (*Message) UnmarshalJSON

func (p *Message) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for Message. It expects data in the compact array format: [Type, RequestID, Method, Params, Timestamp]

This custom unmarshaling ensures backward compatibility with the array-based protocol format while providing a clean struct-based API for Go code.

The method validates that: - The input is a valid JSON array - The array contains exactly 5 elements - Each element has the correct type

Returns an error if the JSON format is invalid or any element has the wrong type.

type Method

type Method string

func (Method) String

func (m Method) String() string

String returns the string representation of the method.

type MsgType

type MsgType uint8
var (
	MsgTypeReq     MsgType = 1
	MsgTypeResp    MsgType = 2
	MsgTypeEvent   MsgType = 3
	MsgTypeRespErr MsgType = 4
)

func (MsgType) String

func (t MsgType) String() string

type Node

type Node interface {
	// ServeHTTP handles incoming HTTP requests and upgrades them to
	// the appropriate transport protocol (e.g., WebSocket). It manages
	// connection lifecycle, including reading requests, routing to
	// handlers, and sending responses.
	ServeHTTP(w http.ResponseWriter, r *http.Request)

	// Handle registers a handler function for a specific RPC method.
	// When a request with the matching method name is received,
	// the handler will be invoked with the request context.
	Handle(method string, handler Handler)

	// Notify sends a server-initiated notification to a specific user.
	// All active connections for the user will receive the notification.
	// If the user has no active connections, the notification is dropped.
	Notify(userID string, method string, params Payload)

	// Use adds global middleware that will be executed for all requests.
	// Middleware is executed in the order it was added, before any
	// method-specific handlers.
	Use(middleware Handler)

	// NewGroup creates a new handler group for organizing related endpoints.
	// Groups can have their own middleware and can be nested to create
	// hierarchical handler structures.
	NewGroup(name string) HandlerGroup
}

Node represents an RPC server that manages client connections and routes messages to appropriate handlers. It provides a foundation for building RPC-based services with support for middleware, authentication, and server-initiated notifications. The interface is transport-agnostic, allowing for different implementations (WebSocket, HTTP/2, etc.).

type NodeV1GetAssetsRequest

type NodeV1GetAssetsRequest struct {
	// BlockchainID filters by blockchain network ID
	BlockchainID *string `json:"blockchain_id,omitempty"`
}

NodeV1GetAssetsRequest retrieves all supported assets with optional chain filter.

type NodeV1GetAssetsResponse

type NodeV1GetAssetsResponse struct {
	// Assets is the list of supported assets
	Assets []AssetV1 `json:"assets"`
}

NodeV1GetAssetsResponse returns the list of supported assets.

type NodeV1GetConfigRequest

type NodeV1GetConfigRequest struct{}

NodeV1GetConfigRequest retrieves broker configuration and supported networks.

type NodeV1GetConfigResponse

type NodeV1GetConfigResponse struct {
	// NodeAddress is the node wallet address
	NodeAddress string `json:"node_address"`
	// NodeVersion is the node software version
	NodeVersion string `json:"node_version"`
	// SupportedSigValidators is the list of supported signature validators identifiers for state sig verification
	SupportedSigValidators []core.ChannelSignerType `json:"supported_sig_validators"`
	// Blockchains is the list of supported networks
	Blockchains []BlockchainInfoV1 `json:"blockchains"`
}

NodeV1GetConfigResponse returns the broker configuration.

type NodeV1PingRequest

type NodeV1PingRequest struct{}

NodeV1PingRequest is a simple connectivity check.

type NodeV1PingResponse

type NodeV1PingResponse struct{}

NodeV1PingResponse is the response to a ping request.

type ObserveConnectionsFn

type ObserveConnectionsFn func(region, origin string, count uint32)

type PaginationMetadataV1

type PaginationMetadataV1 struct {
	// Page is the current page number
	Page uint32 `json:"page"`
	// PerPage is the number of items per page
	PerPage uint32 `json:"per_page"`
	// TotalCount is the total number of items
	TotalCount uint32 `json:"total_count"`
	// PageCount is the total number of pages
	PageCount uint32 `json:"page_count"`
}

PaginationMetadataV1 represents pagination information.

type PaginationParamsV1

type PaginationParamsV1 struct {
	// Offset is the pagination offset (number of items to skip)
	Offset *uint32 `json:"offset,omitempty"`
	// Limit is the number of items to return
	Limit *uint32 `json:"limit,omitempty"`
	// Sort is the sort order (asc/desc)
	Sort *string `json:"sort,omitempty"`
}

PaginationParamsV1 represents pagination request parameters.

type Payload

type Payload map[string]json.RawMessage

Payload represents method-specific parameters as a map of JSON raw messages. This design allows maximum flexibility while maintaining type safety: - Parameters are stored as raw JSON until needed - The Translate method provides type-safe extraction into Go structs - Supports optional parameters and forward compatibility

Example usage:

// Creating params from a struct
params, _ := NewParams(TransferRequest{To: "0x123", Amount: "100"})

// Accessing individual parameters
var amount string
json.Unmarshal(params["amount"], &amount)

// Translating to a struct
var req TransferRequest
params.Translate(&req)

func NewErrorPayload

func NewErrorPayload(errMsg string) Payload

NewErrorPayload creates a Params map containing an error message. This is a convenience function for creating standardized error parameters that follow the protocol's error response convention.

The error message is stored under the "error" key and properly JSON-encoded.

Example usage:

// Creating error params for a validation failure
errParams := NewErrorPayload("invalid address format")
payload := NewPayload(requestID, method, errParams)

// Creating error params from an existing error
if err := validateAmount(amount); err != nil {
    errParams := NewErrorPayload(err.Error())
    response := NewResponse(NewPayload(id, method, errParams))
}

The resulting Params will contain: {"error": "invalid address format"}

func NewPayload

func NewPayload(v any) (Payload, error)

NewPayload creates a Payload map from any JSON-serializable value. This is typically used with structs or maps to create method parameters.

The function works by: 1. Marshaling the input value to JSON 2. Unmarshaling it into a Params map 3. Each field becomes a key with its JSON representation as the value

Example:

type TransferRequest struct {
    From   string `json:"from"`
    To     string `json:"to"`
    Amount string `json:"amount"`
}

req := TransferRequest{
    From:   "0x111...",
    To:     "0x222...",
    Amount: "1000000000000000000",
}

payload, err := NewPayload(req)
// payload now contains: {"from": "0x111...", "to": "0x222...", "amount": "1000000000000000000"}

Returns an error if the value cannot be marshaled to JSON or is not a valid object.

func (Payload) Error

func (p Payload) Error() error

Error extracts and returns an error from the Payload if one exists. This method checks for the standard "error" key in the payload and attempts to unmarshal its value as a string error message.

Returns:

  • An error with the message if the "error" key exists and contains a valid string
  • nil if no error key exists or if the value cannot be unmarshaled

This is typically used when processing response payloads to check for errors:

// In a client processing a response message
if err := message.Payload.Error(); err != nil {
    // The server returned an error
    return fmt.Errorf("RPC error: %w", err)
}

// Process successful response
var result TransferResult
message.Payload.Translate(&result)

This method is designed to work with error params created by NewErrorParams.

func (Payload) Translate

func (p Payload) Translate(v any) error

Translate extracts the parameters into the provided value (typically a struct). This provides type-safe parameter extraction with automatic JSON unmarshaling.

The method works by: 1. Marshaling the Payload map back to JSON 2. Unmarshaling that JSON into the target value 3. Go's JSON unmarshaling handles type conversion and validation

Example:

type BalanceRequest struct {
    Address string `json:"address"`
    Block   string `json:"block,omitempty"`
}

// In an RPC handler:
var req BalanceRequest
if err := message.Payload.Translate(&req); err != nil {
    return rpc.Errorf("invalid parameters: %v", err)
}
// req.Address and req.Block are now populated

The target value should be a pointer to the desired type. Returns an error if the parameters don't match the expected structure.

type SafeStorage

type SafeStorage struct {
	// contains filtered or unexported fields
}

SafeStorage provides thread-safe key-value storage for connection-specific data. Each connection gets its own SafeStorage instance that persists for the connection's lifetime. This enables handlers to store and retrieve session state, authentication tokens, rate limiting counters, or any other per-connection data across multiple requests.

Common use cases:

  • Storing authentication state and policies
  • Caching frequently accessed data
  • Maintaining request counters for rate limiting
  • Storing connection-specific configuration

func NewSafeStorage

func NewSafeStorage() *SafeStorage

NewSafeStorage creates a new thread-safe storage instance. The storage starts empty and can be used immediately for storing connection-specific data.

func (*SafeStorage) Get

func (s *SafeStorage) Get(key string) (any, bool)

Get retrieves a value by key from the storage. Returns the value and true if the key exists, or nil and false if the key is not found. The caller must type-assert the returned value to the expected type.

Example:

if val, ok := storage.Get("auth_token"); ok {
    token := val.(string)
    // Use token...
}

func (*SafeStorage) Set

func (s *SafeStorage) Set(key string, value any)

Set stores a value with the given key in the storage. If the key already exists, its value is overwritten. The value can be of any type. This method is thread-safe and can be called concurrently from multiple goroutines.

Example:

storage.Set("auth_token", "bearer-xyz123")
storage.Set("rate_limit_count", 42)
storage.Set("user_preferences", userPrefs)

type SendResponseFunc

type SendResponseFunc func(method string, params Payload)

SendResponseFunc is a function type for sending server-initiated RPC notifications. Unlike regular responses that reply to client requests, these functions enable the server to push unsolicited messages to clients (e.g., balance updates, connection events). The method parameter specifies the notification type, and params contains the notification data.

type SignedAppStateUpdateV1

type SignedAppStateUpdateV1 struct {
	// AppStateUpdate is the application session state update
	AppStateUpdate AppStateUpdateV1 `json:"app_state_update"`
	// QuorumSigs is the signature quorum for the application session
	QuorumSigs []string `json:"quorum_sigs"`
}

SignedAppStateUpdateV1 represents a signed application session state update.

type StateV1

type StateV1 struct {
	// ID is the deterministic ID (hash) of the state
	ID string `json:"id"`
	// Transition is the state transition that led to this state
	Transition TransitionV1 `json:"transition"`
	// Asset is the asset type of the state
	Asset string `json:"asset"`
	// UserWallet is the user wallet address
	UserWallet string `json:"user_wallet"`
	// Epoch is the user Epoch Index
	Epoch string `json:"epoch"`
	// Version is the version of the state
	Version string `json:"version"`
	// HomeChannelID is the identifier for the home Channel blockchain network
	HomeChannelID *string `json:"home_channel_id,omitempty"`
	// EscrowChannelID is the identifier for the escrow Channel blockchain network
	EscrowChannelID *string `json:"escrow_channel_id,omitempty"`
	// HomeLedger contains user and node balances for the home channel
	HomeLedger LedgerV1 `json:"home_ledger"`
	// EscrowLedger contains user and node balances for the escrow channel
	EscrowLedger *LedgerV1 `json:"escrow_ledger,omitempty"`
	// UserSig is the user signature for the state
	UserSig *string `json:"user_sig,omitempty"`
	// NodeSig is the node signature for the state
	NodeSig *string `json:"node_sig,omitempty"`
}

StateV1 represents the current state of the user stored on Node.

type TokenV1

type TokenV1 struct {
	// Name is the token name
	Name string `json:"name"`
	// Symbol is the token symbol
	Symbol string `json:"symbol"`
	// Address is the token contract address
	Address string `json:"address"`
	// BlockchainID is the blockchain network ID
	BlockchainID string `json:"blockchain_id"`
	// Decimals is the number of decimal places
	Decimals uint8 `json:"decimals"`
}

TokenV1 represents information about a supported token.

type TransactionV1

type TransactionV1 struct {
	// ID is the unique transaction reference
	ID string `json:"id"`
	// Asset is the asset symbol
	Asset string `json:"asset"`
	// TxType is the transaction type
	TxType core.TransactionType `json:"tx_type"`
	// FromAccount is the account that sent the funds
	FromAccount string `json:"from_account"`
	// ToAccount is the account that received the funds
	ToAccount string `json:"to_account"`
	// SenderNewStateID is the ID of the new sender's channel state
	SenderNewStateID *string `json:"sender_new_state_id,omitempty"`
	// ReceiverNewStateID is the ID of the new receiver's channel state
	ReceiverNewStateID *string `json:"receiver_new_state_id,omitempty"`
	// Amount is the transaction amount
	Amount string `json:"amount"`
	// CreatedAt is when the transaction was created
	CreatedAt string `json:"created_at"`
}

TransactionV1 represents a transaction record.

type TransitionV1

type TransitionV1 struct {
	// Type is the type of state transition
	Type core.TransitionType `json:"type"`
	// TxID is the transaction ID associated with the transition
	TxID string `json:"tx_id"`
	// AccountID is the account identifier (varies based on transition type)
	AccountID string `json:"account_id"`
	// Amount is the amount involved in the transition
	Amount string `json:"amount"`
}

TransitionV1 represents a state transition.

type UserV1GetActionAllowancesRequest

type UserV1GetActionAllowancesRequest struct {
	// Wallet is the user's wallet address
	Wallet string `json:"wallet"`
}

UserV1GetActionAllowancesRequest retrieves the current action allowances for a user.

type UserV1GetActionAllowancesResponse

type UserV1GetActionAllowancesResponse struct {
	// Allowances is the list of action allowances for the user
	Allowances []ActionAllowanceV1 `json:"allowances"`
}

UserV1GetActionAllowancesResponse returns the list of action allowances for the user.

type UserV1GetBalancesRequest

type UserV1GetBalancesRequest struct {
	// Wallet is the user's wallet address
	Wallet string `json:"wallet"`
}

UserV1GetBalancesRequest retrieves the balances of the user in YN.

type UserV1GetBalancesResponse

type UserV1GetBalancesResponse struct {
	// Balances is the list of asset balances
	Balances []BalanceEntryV1 `json:"balances"`
}

UserV1GetBalancesResponse returns the list of asset balances.

type UserV1GetTransactionsRequest

type UserV1GetTransactionsRequest struct {
	// Wallet filters by user's wallet address
	Wallet string `json:"wallet"`
	// Asset filters by asset symbol
	Asset *string `json:"asset,omitempty"`
	// TxType filters by transaction type
	TxType *core.TransactionType `json:"tx_type,omitempty"`
	// Pagination contains pagination parameters (offset, limit, sort)
	Pagination *PaginationParamsV1 `json:"pagination,omitempty"`
	// FromTime is the start time filter (Unix timestamp)
	FromTime *uint64 `json:"from_time,omitempty"`
	// ToTime is the end time filter (Unix timestamp)
	ToTime *uint64 `json:"to_time,omitempty"`
}

UserV1GetTransactionsRequest retrieves ledger transaction history with optional filtering.

type UserV1GetTransactionsResponse

type UserV1GetTransactionsResponse struct {
	// Transactions is the list of transactions
	Transactions []TransactionV1 `json:"transactions"`
	// Metadata contains pagination information
	Metadata PaginationMetadataV1 `json:"metadata"`
}

UserV1GetTransactionsResponse returns the list of transactions.

type WebsocketConnection

type WebsocketConnection struct {
	// contains filtered or unexported fields
}

WebsocketConnection implements the Connection interface using WebSocket transport. It manages bidirectional communication, and provides thread-safe operations for concurrent message processing. The connection supports graceful shutdown and automatic cleanup of resources.

Key features:

  • Concurrent read/write operations with separate goroutines
  • Configurable timeouts for write operations
  • Buffered channels for message processing
  • Thread-safe user authentication state management
  • Graceful connection closure with proper resource cleanup
  • Native WebSocket ping/pong keepalive detection

func NewWebsocketConnection

func NewWebsocketConnection(config WebsocketConnectionConfig) (*WebsocketConnection, error)

NewWebsocketConnection creates a new WebsocketConnection instance with the provided configuration. Returns an error if required fields (ConnectionID, WebsocketConn) are missing. Optional fields are set to sensible defaults if not provided.

func (*WebsocketConnection) ConnectionID

func (conn *WebsocketConnection) ConnectionID() string

ConnectionID returns the unique identifier for this connection.

func (*WebsocketConnection) Origin

func (conn *WebsocketConnection) Origin() string

Origin returns the origin of the connection, such as the client's IP address or other identifying information.

func (*WebsocketConnection) RawRequests

func (conn *WebsocketConnection) RawRequests() <-chan []byte

RawRequests returns the channel for processing incoming requests.

func (*WebsocketConnection) Serve

func (conn *WebsocketConnection) Serve(parentCtx context.Context, handleClosure func(error))

Serve starts the connection's lifecycle by spawning concurrent goroutines. This method:

  • Spawns three goroutines: one for reading messages, one for writing messages, and one for monitoring connection closure signals
  • Returns immediately after starting the goroutines
  • Spawns an additional goroutine that waits for all operations to complete and then invokes handleClosure with any error that occurred

The handleClosure callback is guaranteed to be called exactly once when the connection terminates. The method is idempotent - calling it multiple times will immediately invoke handleClosure without starting duplicate goroutines.

func (*WebsocketConnection) WriteRawResponse

func (conn *WebsocketConnection) WriteRawResponse(message []byte) bool

WriteRawResponse attempts to queue a message for sending to the client. The method uses a timeout to prevent blocking on unresponsive clients. If the message cannot be queued within the timeout duration:

  • The method returns false
  • A close signal is sent to trigger connection shutdown
  • This prevents resource exhaustion from slow or disconnected clients

Returns true if the message was successfully queued for sending.

type WebsocketConnectionConfig

type WebsocketConnectionConfig struct {
	// ConnectionID is the unique identifier for this connection (required)
	ConnectionID string
	// Origin is the origin of the connection, such as the client's IP address (optional)
	Origin string
	// WebsocketConn is the underlying WebSocket connection (required)
	WebsocketConn GorillaWsConnectionAdapter

	// WriteTimeout is the maximum duration to wait for a write operation (default: 5s)
	WriteTimeout time.Duration
	// WriteBufferSize is the capacity of the outgoing message buffer (default: 10)
	WriteBufferSize int
	// ProcessBufferSize is the capacity of the incoming message buffer (default: 10)
	ProcessBufferSize int
	// PingInterval is how often to send ping frames to clients (default: 5s).
	PingInterval time.Duration
	// PongTimeout is the maximum duration to wait for a pong response from the client (default: 10s).
	// If no pong is received within this duration, the connection is considered dead.
	PongTimeout time.Duration
	// Logger for connection events (default: no-op logger)
	Logger log.Logger
	// OnMessageSentHandler is called after a message is successfully sent (optional)
	OnMessageSentHandler func([]byte)
}

WebsocketConnectionConfig contains configuration options for creating a new WebsocketConnection. All fields except ConnectionID and WebsocketConn have sensible defaults.

type WebsocketDialer

type WebsocketDialer struct {
	// contains filtered or unexported fields
}

WebsocketDialer implements the Dialer interface using WebSocket connections. It provides thread-safe RPC communication with automatic ping handling.

func NewWebsocketDialer

func NewWebsocketDialer(cfg WebsocketDialerConfig) *WebsocketDialer

NewWebsocketDialer creates a new WebSocket dialer with the given configuration

func (*WebsocketDialer) Call

func (d *WebsocketDialer) Call(ctx context.Context, req *Message) (*Message, error)

Call sends an RPC request and waits for a response. The request must have a unique RequestID that identifies this call. The method is thread-safe and can be called concurrently.

The context can be used to set a timeout for the request:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := dialer.Call(ctx, request)

func (*WebsocketDialer) Dial

func (d *WebsocketDialer) Dial(parentCtx context.Context, url string, handleClosure func(err error)) error

Dial establishes a WebSocket connection to the specified URL. This method blocks until the connection is closed, so it should typically be called in a goroutine. It starts three background goroutines: - One to handle context cancellation - One to read and route incoming messages - One to send periodic ping messages

Example:

dialer := NewWebsocketDialer(DefaultWebsocketDialerConfig)
go dialer.Dial(ctx, "ws://localhost:8080/ws", func(err error) {
    if err != nil {
        log.Error("Connection closed", "error", err)
    }
})

func (*WebsocketDialer) EventCh

func (d *WebsocketDialer) EventCh() <-chan *Message

EventCh returns a read-only channel for receiving unsolicited events. Events are responses that don't match any pending request ID. The channel will receive nil when the connection is closed.

Example:

for event := range dialer.EventCh() {
    if event == nil {
        // Connection closed
        break
    }
    // Handle event
    log.Info("Received event", "method", event.Method)
}

func (*WebsocketDialer) IsConnected

func (d *WebsocketDialer) IsConnected() bool

IsConnected returns true if the dialer has an active connection

type WebsocketDialerConfig

type WebsocketDialerConfig struct {
	// HandshakeTimeout is the duration to wait for the WebSocket handshake to complete
	HandshakeTimeout time.Duration

	// PingTimeout is how long to wait for a ping from the server before considering the connection dead.
	// The server sends periodic pings to keep connections alive and detect dead clients.
	PingTimeout time.Duration

	// EventChanSize is the buffer size for the event channel
	// A larger buffer prevents blocking when processing many unsolicited events
	EventChanSize int
}

WebsocketDialerConfig contains configuration options for the WebSocket dialer

type WebsocketHandlerGroup

type WebsocketHandlerGroup struct {
	// contains filtered or unexported fields
}

WebsocketHandlerGroup implements the HandlerGroup interface for organizing related handlers with shared middleware. Groups support nesting, allowing for hierarchical organization of endpoints with inherited middleware chains.

When a request matches a handler in a group, the middleware chain is:

  1. Global middleware (from Node.Use)
  2. Parent group middleware (if nested)
  3. This group's middleware
  4. The method handler

This enables fine-grained control over request processing pipelines.

func (*WebsocketHandlerGroup) Handle

func (hg *WebsocketHandlerGroup) Handle(method string, handler Handler)

Handle registers a handler for the specified RPC method within this group. The handler will execute after all applicable middleware:

  • Global middleware
  • Parent group middleware (for nested groups)
  • This group's middleware

The method parameter must be unique across the entire node.

func (*WebsocketHandlerGroup) NewGroup

func (hg *WebsocketHandlerGroup) NewGroup(name string) HandlerGroup

NewGroup creates a nested handler group within this group. The nested group inherits the middleware chain from all parent groups, allowing for progressive middleware application.

Example:

api := node.NewGroup("api")
api.Use(apiVersionMiddleware)

v1 := api.NewGroup("v1")
v1.Use(v1AuthMiddleware)
// Handlers in v1 group will execute: global → api → v1 middleware

func (*WebsocketHandlerGroup) Use

func (hg *WebsocketHandlerGroup) Use(middleware Handler)

Use adds middleware to this handler group. The middleware will execute for all handlers in this group and any nested groups. Middleware is executed in the order it was added.

Panics if middleware is nil.

type WebsocketNode

type WebsocketNode struct {
	// contains filtered or unexported fields
}

WebsocketNode implements the Node interface using WebSocket as the transport layer. It provides a complete RPC server implementation with the following features:

  • WebSocket connection management with automatic cleanup
  • Request routing based on method names
  • Middleware support at global and group levels
  • Cryptographic signing of all responses
  • Connection authentication and re-authentication
  • Server-initiated notifications to specific users
  • Configurable timeouts and buffer sizes
  • Structured logging for debugging and monitoring

The node automatically handles connection lifecycle, including:

  • WebSocket protocol upgrade
  • Concurrent message processing
  • Graceful connection shutdown
  • Resource cleanup on disconnection

func NewWebsocketNode

func NewWebsocketNode(config WebsocketNodeConfig) (*WebsocketNode, error)

NewWebsocketNode creates a new WebsocketNode instance with the provided configuration. The node is ready to accept WebSocket connections after creation.

Required configuration:

  • Logger: Used for structured logging

Returns an error if required configuration is missing.

func (*WebsocketNode) Handle

func (wn *WebsocketNode) Handle(method string, handler Handler)

Handle registers a handler function for the specified RPC method. When a request with a matching method name is received, the handler will be invoked with a Context containing the request information.

The handler executes after all global middleware registered with Use().

Panics if:

  • method is empty
  • handler is nil

func (*WebsocketNode) NewGroup

func (wn *WebsocketNode) NewGroup(name string) HandlerGroup

NewGroup creates a new handler group with the specified name. Groups provide a way to organize related handlers and apply common middleware. Groups can be nested to create hierarchical structures.

Example:

// Create a group for authenticated endpoints
privateGroup := node.NewGroup("private")
privateGroup.Use(authMiddleware)
privateGroup.Handle("get_balance", handleGetBalance)

// Create a nested group with additional middleware
adminGroup := privateGroup.NewGroup("admin")
adminGroup.Use(adminAuthMiddleware)
adminGroup.Handle("manage_users", handleManageUsers)

func (*WebsocketNode) Notify

func (wn *WebsocketNode) Notify(userID, method string, params Payload)

Notify sends a server-initiated notification to all connections of a specific user. This enables the server to push updates to clients without a prior request. Common use cases include:

  • Balance updates after transactions
  • Status changes in long-running operations
  • Real-time notifications for user events

The notification is sent to all active connections for the user. If the user has no active connections, the notification is silently dropped.

Notifications have RequestID=0 to distinguish them from responses.

func (*WebsocketNode) ServeHTTP

func (wn *WebsocketNode) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler, making the node compatible with standard HTTP servers. This method:

  1. Upgrades incoming HTTP requests to WebSocket connections
  2. Creates a unique connection ID and manages connection state
  3. Spawns goroutines for concurrent message processing
  4. Invokes lifecycle callbacks (OnConnect, OnDisconnect, etc.)
  5. Blocks until the connection is closed

Each connection runs independently with its own goroutines for:

  • Reading incoming messages
  • Processing requests and routing to handlers
  • Writing outgoing responses
  • Monitoring connection health

The method ensures proper cleanup when connections close, including removing the connection from the hub and invoking disconnect callbacks.

func (*WebsocketNode) Use

func (wn *WebsocketNode) Use(middleware Handler)

Use adds global middleware that executes for all requests. Middleware is executed in the order it was registered, before any method-specific handlers. Common middleware includes:

  • Authentication checks
  • Request logging
  • Rate limiting
  • Request validation

Example:

node.Use(loggingMiddleware)
node.Use(rateLimitMiddleware)
node.Use(authMiddleware)

type WebsocketNodeConfig

type WebsocketNodeConfig struct {
	// Logger is used for structured logging throughout the node (required).
	Logger log.Logger

	// Connection lifecycle callbacks:
	// ObserveConnections is called with the current number of active connections whenever a connection is established or closed.
	ObserveConnections ObserveConnectionsFn

	// WsUpgraderReadBufferSize sets the read buffer size for the WebSocket upgrader (default: 1024).
	WsUpgraderReadBufferSize int
	// WsUpgraderWriteBufferSize sets the write buffer size for the WebSocket upgrader (default: 1024).
	WsUpgraderWriteBufferSize int
	// WsUpgraderCheckOrigin validates the origin of incoming WebSocket requests.
	// Default allows all origins; implement this for CORS protection.
	WsUpgraderCheckOrigin func(r *http.Request) bool

	// WsConnWriteTimeout is the maximum time to wait for a write operation (default: 5s).
	// Connections that exceed this timeout are considered unresponsive and closed.
	WsConnWriteTimeout time.Duration
	// WsConnWriteBufferSize is the capacity of each connection's outgoing message queue (default: 10).
	WsConnWriteBufferSize int
	// WsConnProcessBufferSize is the capacity of each connection's incoming message queue (default: 10).
	WsConnProcessBufferSize int
}

WebsocketNodeConfig contains all configuration options for creating a WebsocketNode. The only required field is Logger; all others have sensible defaults.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL