sdk

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: 17 Imported by: 0

README

Go Reference

Clearnode Go SDK

Go SDK for Clearnode payment channels providing both high-level and low-level operations in a unified client:

  • State Operations: Deposit, Withdraw, Transfer, CloseHomeChannel, Acknowledge - build and co-sign states off-chain
  • Blockchain Settlement: Checkpoint - the single entry point for all on-chain transactions
  • Low-Level Operations: Direct RPC access for custom flows and advanced use cases

Method Cheat Sheet

State Operations (Off-Chain)
client.Deposit(ctx, blockchainID, asset, amount)      // Prepare deposit state
client.Withdraw(ctx, blockchainID, asset, amount)     // Prepare withdrawal state
client.Transfer(ctx, recipientWallet, asset, amount)  // Prepare transfer state
client.CloseHomeChannel(ctx, asset)                   // Prepare finalize state
client.Acknowledge(ctx, asset)                        // Acknowledge received state
Blockchain Settlement
client.Checkpoint(ctx, asset)                         // Settle latest state on-chain
client.Challenge(ctx, state)                          // Submit on-chain challenge
client.ApproveToken(ctx, chainID, asset, amount)      // Approve ChannelHub to spend tokens
client.GetOnChainBalance(ctx, chainID, asset, wallet) // Query on-chain token balance
Node Information
client.Ping(ctx)                    // Health check
client.GetConfig(ctx)               // Node configuration
client.GetBlockchains(ctx)          // Supported blockchains
client.GetAssets(ctx, blockchainID) // Supported assets
User Queries
client.GetBalances(ctx, wallet)             // User balances
client.GetTransactions(ctx, wallet, opts)   // Transaction history
Channel Queries
client.GetHomeChannel(ctx, wallet, asset)       // Home channel info
client.GetEscrowChannel(ctx, escrowChannelID)   // Escrow channel info
client.GetLatestState(ctx, wallet, asset, onlySigned) // Latest state
App Registry
client.GetApps(ctx, opts)                              // List registered apps
client.RegisterApp(ctx, appID, metadata, approvalNotRequired) // Register new app
App Sessions
client.GetAppSessions(ctx, opts)                              // List sessions
client.GetAppDefinition(ctx, appSessionID)                    // Session definition
client.CreateAppSession(ctx, definition, sessionData, sigs)   // Create session
client.CreateAppSession(ctx, def, data, sigs, opts)           // Create with owner approval
client.SubmitAppSessionDeposit(ctx, update, sigs, asset, amount) // Deposit to session
client.SubmitAppState(ctx, update, sigs)                      // Update session
client.RebalanceAppSessions(ctx, signedUpdates)               // Atomic rebalance
Session Keys — App Sessions
client.SignSessionKeyState(state)                                   // Sign an app session key state
client.SubmitAppSessionKeyState(ctx, state)                         // Register/update app session key
client.GetLastAppKeyStates(ctx, userAddress, opts)                  // Get active app session key states
Session Keys — Channels
client.SignChannelSessionKeyState(state)                            // Sign a channel session key state
client.SubmitChannelSessionKeyState(ctx, state)                     // Register/update channel session key
client.GetLastChannelKeyStates(ctx, userAddress, opts)              // Get active channel session key states
Shared Utilities
client.Close()                          // Close connection
client.WaitCh()                         // Connection monitor channel
client.SignState(state)                 // Sign a state (advanced)
client.GetUserAddress()                 // Get signer's address
client.SetHomeBlockchain(asset, chainID) // Set default blockchain for asset

Quick Start

Unified Client (High-Level + Low-Level)
package main

import (
    "context"
    "github.com/layer-3/nitrolite/pkg/core"
    "github.com/layer-3/nitrolite/pkg/sign"
    sdk "github.com/layer-3/nitrolite/sdk/go"
    "github.com/shopspring/decimal"
)

func main() {
    // Create signers from private key
    msgSigner, _ := sign.NewEthereumMsgSigner(privateKeyHex)
    stateSigner, _ := core.NewChannelDefaultSigner(msgSigner)
    txSigner, _ := sign.NewEthereumRawSigner(privateKeyHex)

    // Create unified client
    client, _ := sdk.NewClient(
        "wss://clearnode-sandbox.yellow.org/v1/ws",
        stateSigner,
        txSigner,
        sdk.WithBlockchainRPC(80002, "https://polygon-amoy.alchemy.com/v2/KEY"),
    )
    defer client.Close()

    ctx := context.Background()

    // Step 1: Build and co-sign states off-chain
    state, _ := client.Deposit(ctx, 80002, "usdc", decimal.NewFromInt(100))
    fmt.Printf("Deposit state version: %d\n", state.Version)

    // Step 2: Settle on-chain via Checkpoint
    txHash, _ := client.Checkpoint(ctx, "usdc")
    fmt.Printf("On-chain tx: %s\n", txHash)

    // Transfer (off-chain only, no Checkpoint needed for existing channels)
    state, _ = client.Transfer(ctx, "0xRecipient...", "usdc", decimal.NewFromInt(50))

    // Low-level operations - same client
    config, _ := client.GetConfig(ctx)
    balances, _ := client.GetBalances(ctx, walletAddress)
}

Architecture

sdk/go/
├── client.go         # Core client, constructors, high-level operations
├── node.go           # Node information methods
├── user.go           # User query methods
├── channel.go        # Channel and state management
├── app_registry.go   # App registry methods
├── app_session.go    # App session methods
├── asset_cache.go    # Asset lookup and caching
├── config.go         # Configuration options
├── doc.go            # Package documentation
└── utils.go          # Type conversions

Client API

Creating a Client
// Step 1: Create signers from private key
msgSigner, err := sign.NewEthereumMsgSigner("0x1234...")
if err != nil {
    log.Fatal(err)
}

// Wrap with ChannelDefaultSigner (prepends 0x00 type byte)
stateSigner, err := core.NewChannelDefaultSigner(msgSigner)
if err != nil {
    log.Fatal(err)
}

txSigner, err := sign.NewEthereumRawSigner("0x1234...")
if err != nil {
    log.Fatal(err)
}

// Step 2: Create unified client
client, err := sdk.NewClient(
    wsURL,
    stateSigner,  // core.ChannelSigner for signing channel states
    txSigner,     // sign.Signer for signing blockchain transactions
    sdk.WithBlockchainRPC(chainID, rpcURL), // Required for Checkpoint
    sdk.WithHandshakeTimeout(10*time.Second),
    sdk.WithPingInterval(5*time.Second),
)

// Step 3: (Optional) Set home blockchain for assets
// Required for Transfer operations that may trigger channel creation
err = client.SetHomeBlockchain("usdc", 80002)
if err != nil {
    log.Fatal(err)
}
Configuring Home Blockchain
SetHomeBlockchain(asset, blockchainID) error

Sets the default blockchain network for a specific asset. This is required for Transfer() operations that may trigger channel creation, as Transfer doesn't accept a blockchain ID parameter.

err := client.SetHomeBlockchain("usdc", 80002)
if err != nil {
    log.Fatal(err)
}

Important Notes:

  • This mapping is immutable once set for the client instance
  • The asset must be supported on the specified blockchain
  • Required before calling Transfer() on a new channel
State Operations

All state operations build and co-sign a state off-chain. They return (*core.State, error). Use Checkpoint to settle the state on-chain.

Deposit(ctx, blockchainID, asset, amount) (*core.State, error)

Prepares a deposit state. Creates a new channel if none exists, otherwise advances the existing state.

state, err := client.Deposit(ctx, 80002, "usdc", decimal.NewFromInt(100))
txHash, err := client.Checkpoint(ctx, "usdc") // settle on-chain

Requirements:

  • Sufficient token balance (checked on-chain during Checkpoint)
Withdraw(ctx, blockchainID, asset, amount) (*core.State, error)

Prepares a withdrawal state to remove funds from the channel.

state, err := client.Withdraw(ctx, 80002, "usdc", decimal.NewFromInt(25))
txHash, err := client.Checkpoint(ctx, "usdc") // settle on-chain

Requirements:

  • Existing channel with sufficient balance
Transfer(ctx, recipientWallet, asset, amount) (*core.State, error)

Prepares an off-chain transfer to another wallet. For existing channels, no Checkpoint is needed.

state, err := client.Transfer(ctx, "0xRecipient...", "usdc", decimal.NewFromInt(50))

Requirements:

  • Existing channel with sufficient balance OR
  • Home blockchain configured via SetHomeBlockchain() (for new channels)
CloseHomeChannel(ctx, asset) (*core.State, error)

Prepares a finalize state to close the user's channel.

state, err := client.CloseHomeChannel(ctx, "usdc")
txHash, err := client.Checkpoint(ctx, "usdc") // close on-chain

Requirements:

  • Existing channel (user must have deposited first)
Acknowledge(ctx, asset) (*core.State, error)

Acknowledges a received state (e.g., after receiving a transfer).

state, err := client.Acknowledge(ctx, "usdc")

Requirements:

  • Home blockchain configured via SetHomeBlockchain() when no channel exists
Blockchain Settlement
Checkpoint(ctx, asset) (txHash, error)

Settles the latest co-signed state on-chain. This is the single entry point for all blockchain transactions. Based on the transition type and on-chain channel status, it calls the appropriate blockchain method:

  • Channel not on-chain (status Void): Creates the channel
  • Deposit/Withdrawal on existing channel: Checkpoints the state
  • Finalize: Closes the channel
txHash, err := client.Checkpoint(ctx, "usdc")

Requirements:

  • Blockchain RPC configured via WithBlockchainRPC
  • A co-signed state must exist (call Deposit, Withdraw, etc. first)
  • Sufficient gas for the blockchain transaction
Challenge(ctx, state) (txHash, error)

Submits an on-chain challenge for a channel using a co-signed state. A challenge initiates a dispute period on-chain. If the counterparty does not respond with a higher-versioned state before the challenge period expires, the channel can be closed with the challenged state.

state, err := client.GetLatestState(ctx, wallet, "usdc", true)
txHash, err := client.Challenge(ctx, *state)

Requirements:

  • Blockchain RPC configured via WithBlockchainRPC
  • State must have both user and node signatures
  • State must have a HomeChannelID
ApproveToken(ctx, chainID, asset, amount) (txHash, error)

Approves the ChannelHub contract to spend ERC-20 tokens on behalf of the user. This is required before depositing ERC-20 tokens. Native tokens (e.g., ETH) do not require approval.

txHash, err := client.ApproveToken(ctx, 80002, "usdc", decimal.NewFromInt(1000))

Requirements:

  • Blockchain RPC configured via WithBlockchainRPC
GetOnChainBalance(ctx, chainID, asset, wallet) (decimal.Decimal, error)

Queries the on-chain token balance (ERC-20 or native) for a wallet on a specific blockchain. The returned value is already adjusted for token decimals.

balance, err := client.GetOnChainBalance(ctx, 80002, "usdc", "0x1234...")
fmt.Printf("On-chain balance: %s\n", balance)

Requirements:

  • Blockchain RPC configured via WithBlockchainRPC

Low-Level API

All low-level RPC methods are available on the same Client instance.

Node Information
err := client.Ping(ctx)
config, err := client.GetConfig(ctx)
blockchains, err := client.GetBlockchains(ctx)
assets, err := client.GetAssets(ctx, &blockchainID) // or nil for all
User Data
balances, err := client.GetBalances(ctx, wallet)
txs, meta, err := client.GetTransactions(ctx, wallet, opts)
Channel Queries
channel, err := client.GetHomeChannel(ctx, wallet, asset)
channel, err := client.GetEscrowChannel(ctx, escrowChannelID)
state, err := client.GetLatestState(ctx, wallet, asset, onlySigned)

Note: State submission and channel creation are handled internally by state operations (Deposit, Withdraw, Transfer). On-chain settlement is handled by Checkpoint.

App Registry
// List registered applications with optional filtering
apps, meta, err := client.GetApps(ctx, &sdk.GetAppsOptions{
    AppID:       &appID,
    OwnerWallet: &wallet,
})

// Register a new application
err := client.RegisterApp(ctx, "my-app", `{"name": "My App"}`, false)
App Sessions (Low-Level)
sessions, meta, err := client.GetAppSessions(ctx, opts)
def, err := client.GetAppDefinition(ctx, appSessionID)
sessionID, version, status, err := client.CreateAppSession(ctx, def, data, sigs)
nodeSig, err := client.SubmitAppSessionDeposit(ctx, update, sigs, asset, amount)
err := client.SubmitAppState(ctx, update, sigs)
batchID, err := client.RebalanceAppSessions(ctx, signedUpdates)
Owner Approval for App Session Creation

When an app is registered with creationApprovalNotRequired: false, the app owner must sign the session creation request. Pass the owner's signature via CreateAppSessionOptions:

// Owner signs the create request using their app session signer
ownerSig, _ := ownerAppSessionSigner.Sign(createRequest)

sessionID, _, _, err := client.CreateAppSession(ctx, def, data, sigs,
    sdk.CreateAppSessionOptions{OwnerSig: ownerSig.String()},
)
App Session Signers (pkg/app)

App session operations require signatures with a type byte prefix, similar to channel signers:

Type Byte Constructor Usage
Wallet 0xA1 app.NewAppSessionWalletSignerV1(msgSigner) Main wallet signs app session operations
Session Key 0xA2 app.NewAppSessionKeySignerV1(msgSigner) Delegated session key signs on behalf of wallet
// Create app session wallet signer
msgSigner, _ := sign.NewEthereumMsgSigner(privateKeyHex)
appSessionSigner, _ := app.NewAppSessionWalletSignerV1(msgSigner)

// Sign app session operations (create, deposit, state updates, etc.)
sig, _ := appSessionSigner.Sign(packedRequest)
Session Keys — App Sessions
// Sign and submit an app session key state
state := app.AppSessionKeyStateV1{
    UserAddress:    client.GetUserAddress(),
    SessionKey:     "0xSessionKey...",
    Version:        1,
    ApplicationIDs: []string{"app1"},
    AppSessionIDs:  []string{},
    ExpiresAt:      time.Now().Add(24 * time.Hour),
}
sig, err := client.SignSessionKeyState(state)
state.UserSig = sig
err = client.SubmitAppSessionKeyState(ctx, state)

// Query active app session key states
states, err := client.GetLastAppKeyStates(ctx, userAddress, nil)
states, err := client.GetLastAppKeyStates(ctx, userAddress, &sdk.GetLastKeyStatesOptions{
    SessionKey: &sessionKeyAddr,
})
Session Keys — Channels
// Sign and submit a channel session key state
state := core.ChannelSessionKeyStateV1{
    UserAddress: client.GetUserAddress(),
    SessionKey:  "0xSessionKey...",
    Version:     1,
    Assets:      []string{"usdc", "weth"},
    ExpiresAt:   time.Now().Add(24 * time.Hour),
}
sig, err := client.SignChannelSessionKeyState(state)
state.UserSig = sig
err = client.SubmitChannelSessionKeyState(ctx, state)

// Query active channel session key states
states, err := client.GetLastChannelKeyStates(ctx, userAddress, nil)
states, err := client.GetLastChannelKeyStates(ctx, userAddress, &sdk.GetLastChannelKeyStatesOptions{
    SessionKey: &sessionKeyAddr,
})

Key Concepts

State Management

Payment channels use versioned states signed by both user and node. The SDK uses a two-step pattern:

// Step 1: Build and co-sign state off-chain
state, _ := client.Deposit(...)   // Returns *core.State
state, _ = client.Withdraw(...)   // Returns *core.State
state, _ = client.Transfer(...)   // Returns *core.State

// Step 2: Settle on-chain (when needed)
txHash, _ := client.Checkpoint(ctx, "usdc")

State Flow (Internal):

  1. Get latest state with GetLatestState()
  2. Create next state with state.NextState()
  3. Apply transition (deposit, withdraw, transfer, etc.)
  4. Sign state with SignState()
  5. Submit to node for co-signing
  6. Return co-signed state

On-chain settlement is handled separately by Checkpoint.

Signing

States are signed using ECDSA with EIP-155 via pkg/sign:

// Create signers from private key
stateSigner, err := sign.NewEthereumMsgSigner(privateKeyHex)  // For channel states
txSigner, err := sign.NewEthereumRawSigner(privateKeyHex)     // For blockchain transactions

// Get address
address := txSigner.PublicKey().Address().String()

Signing Process:

  1. State -> ABI Encode (via core.PackState)
  2. Packed State -> Keccak256 Hash
  3. Hash -> ECDSA Sign (via signer.Sign)
  4. Result: 65-byte signature (R || S || V)

Two Signer Types:

  • EthereumMsgSigner: Signs channel state updates (off-chain signatures)
  • EthereumRawSigner: Signs blockchain transactions (on-chain operations)
Channel Signers (pkg/core)

The SDK wraps raw signers with a ChannelSigner interface that prepends a type byte to every signature. This allows the on-chain contract to dispatch signature verification to the correct validator.

// ChannelSigner interface (in pkg/core)
type ChannelSigner interface {
    sign.Signer
    Type() ChannelSignerType
}

Two channel signer types:

Type Byte Struct Usage
Default 0x00 core.ChannelDefaultSigner Main wallet signs directly. Signature = 0x00 || EIP-191 sig.
Session Key 0x01 core.ChannelSessionKeySignerV1 Delegated session key signs on behalf of main wallet. Signature = 0x01 || ABI-encoded auth + session key sig.

Creating a channel signer:

// Default signer (wraps EthereumMsgSigner with 0x00 prefix)
msgSigner, _ := sign.NewEthereumMsgSigner(privateKeyHex)
channelSigner, _ := core.NewChannelDefaultSigner(msgSigner)

// Pass to NewClient as the stateSigner parameter
client, _ := sdk.NewClient(wsURL, channelSigner, txSigner, opts...)

The NewClient constructor expects a core.ChannelSigner for the stateSigner parameter. When using sign.NewEthereumMsgSigner directly, it must first be wrapped with core.NewChannelDefaultSigner (or core.ChannelSessionKeySignerV1 for session key operation).

Channel Lifecycle
  1. Void: No channel exists
  2. Create: Deposit creates channel on-chain
  3. Open: Channel active, can deposit/withdraw/transfer
  4. Challenged: Dispute initiated (advanced)
  5. Closed: Channel finalized (advanced)

When to Use State Operations vs Low-Level Operations

Use State Operations When:
  • Building user-facing applications
  • Need simple deposit/withdraw/transfer
  • Want automatic state management with two-step pattern
  • Don't need custom flows
Use Low-Level Operations When:
  • Building infrastructure/tooling
  • Implementing custom state transitions
  • Need fine-grained control
  • Working with app sessions directly

Error Handling

All errors include context:

state, err := client.Deposit(ctx, 80002, "usdc", amount)
if err != nil {
    log.Printf("State error: %v", err)
}

txHash, err := client.Checkpoint(ctx, "usdc")
if err != nil {
    // Error: "failed to create channel on blockchain: insufficient balance"
    log.Printf("Checkpoint error: %v", err)
}

Common errors:

  • "home blockchain not set for asset" - Missing SetHomeBlockchain for new channel creation
  • "blockchain RPC not configured for chain" - Missing WithBlockchainRPC (for Checkpoint)
  • "no channel exists for asset" - Checkpoint called without a co-signed state
  • "insufficient balance" - Not enough funds in channel/wallet
  • "failed to sign state" - Invalid private key or state
  • "transition type ... does not require a blockchain operation" - Checkpoint called on unsupported transition

Configuration Options

sdk.WithBlockchainRPC(chainID, rpcURL)    // Configure blockchain RPC (required for Checkpoint)
sdk.WithHandshakeTimeout(duration)         // Connection timeout (default: 5s)
sdk.WithPingInterval(duration)             // Keepalive interval (default: 5s)
sdk.WithErrorHandler(func(error))          // Connection error handler

Examples

App Sessions Example

Comprehensive example demonstrating app session lifecycle and operations.

See examples/app_sessions/lifecycle.go

cd examples/app_sessions
go run lifecycle.go

This example demonstrates:

  • Registering apps in the app registry (with and without owner approval)
  • Creating app sessions with single and multiple participants
  • Owner approval for app session creation
  • Session key delegation for app session participants
  • Depositing assets into app sessions
  • Operating on app session state (redistributing allocations)
  • Withdrawing from app sessions
  • Closing app sessions
  • Fail case: attempting to create a session for an unregistered app

The example walks through a complete multi-party app session scenario with three wallets.

Types

All types are imported from pkg/core and pkg/app:

// Core types
core.State           // Channel state
core.Channel         // Channel info
core.Transition      // State transition
core.Transaction     // Transaction record
core.Asset           // Asset info
core.Token           // Token implementation
core.Blockchain      // Blockchain info

// Core channel session key types
core.ChannelSessionKeyStateV1  // Channel session key state
// Fields: UserAddress, SessionKey, Version (uint64), Assets []string,
//         ExpiresAt (time.Time), UserSig string

// App registry types
app.AppV1                 // Application definition
app.AppInfoV1             // Application info with timestamps

// App session types
app.AppSessionInfoV1      // Session info
app.AppDefinitionV1       // Session definition
app.AppStateUpdateV1      // Session update
app.AppSessionKeyStateV1  // App session key state
// Fields: UserAddress, SessionKey, Version (uint64), ApplicationIDs []string,
//         AppSessionIDs []string, ExpiresAt (time.Time), UserSig string

Operation Internals

For understanding how operations work under the hood:

Deposit Flow (New Channel)
  1. Create channel definition
  2. Create void state
  3. Set home ledger (token, chain)
  4. Apply deposit transition
  5. Sign state
  6. Request channel creation from node (co-sign)
  7. Return co-signed state
Deposit Flow (Existing Channel)
  1. Get latest state
  2. Create next state
  3. Apply deposit transition
  4. Sign state
  5. Submit to node (co-sign)
  6. Return co-signed state
Withdraw Flow
  1. Get latest state
  2. Create next state
  3. Apply withdrawal transition
  4. Sign state
  5. Submit to node (co-sign)
  6. Return co-signed state
Transfer Flow
  1. Get latest state
  2. Create next state
  3. Apply transfer transition
  4. Sign state
  5. Submit to node (co-sign)
  6. Return co-signed state
CloseHomeChannel Flow
  1. Get latest state
  2. Verify channel exists
  3. Create next state
  4. Apply finalize transition
  5. Sign state
  6. Submit to node (co-sign)
  7. Return co-signed state
Checkpoint Flow
  1. Get latest signed state (both signatures)
  2. Determine blockchain ID from state's home ledger
  3. Get on-chain channel status
  4. Route based on transition type + status:
    • Void channel -> blockchainClient.Create()
    • Existing channel -> blockchainClient.Checkpoint()
    • Finalize -> blockchainClient.Close()
  5. Return transaction hash

Requirements

  • Go 1.21+
  • Running Clearnode instance
  • Blockchain RPC endpoint (for Checkpoint settlement)

License

Part of the Nitrolite project.

Documentation

Overview

Package sdk provides the official Go client for the Nitrolite Clearnode API.

The SDK offers a unified interface for interacting with Clearnode payment channels, supporting both high-level state operations and low-level RPC access. It simplifies the process of managing channel states, performing off-chain transactions, and settling on-chain when necessary.

Key Features

  • Unified Client: A single `Client` struct for all operations.
  • State Operations: High-level methods (`Deposit`, `Withdraw`, `Transfer`, `CloseHomeChannel`, `Acknowledge`) to build and co-sign channel states off-chain.
  • Blockchain Settlement: A single `Checkpoint` method to settle the latest state on-chain (creating channels, depositing, withdrawing, or finalizing).
  • Low-Level Access: Direct access to Clearnode RPC methods for advanced use cases (e.g., querying node config, balances, channel info).
  • App Sessions: Comprehensive support for creating and managing application sessions.
  • Session Keys: Support for registering and using session keys for delegated signing.

Usage

To use the SDK, create a `Client` instance with your Clearnode WebSocket URL and signers. You can configure blockchain RPCs for on-chain operations.

package main

import (
	"context"
	"log"
	"time"

	"github.com/layer-3/nitrolite/pkg/sign"
	sdk "github.com/layer-3/nitrolite/sdk/go"
	"github.com/shopspring/decimal"
)

func main() {
	// Initialize signers
	privateKeyHex := "YOUR_PRIVATE_KEY_HEX"
	stateSigner, err := sign.NewEthereumMsgSigner(privateKeyHex)
	if err != nil {
		log.Fatal(err)
	}
	txSigner, err := sign.NewEthereumRawSigner(privateKeyHex)
	if err != nil {
		log.Fatal(err)
	}

	// Create Client
	client, err := sdk.NewClient(
		"wss://clearnode-sandbox.yellow.org/v1/ws",
		stateSigner,
		txSigner,
		sdk.WithBlockchainRPC(80002, "https://rpc-endpoint.example.com"),
		sdk.WithHandshakeTimeout(10*time.Second),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	ctx := context.Background()

	// 1. Deposit (Off-chain state preparation)
	// This creates a new state reflecting the deposit intent.
	state, err := client.Deposit(ctx, 80002, "usdc", decimal.NewFromInt(100))
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Deposit prepared. New state version: %d", state.Version)

	// 2. Settlement (On-chain execution)
	// This submits the transaction to the blockchain to create the channel or deposit funds.
	txHash, err := client.Checkpoint(ctx, "usdc")
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("On-chain transaction hash: %s", txHash)

	// 3. Transfer (Off-chain transaction)
	// Transfers are instant and don't require immediate on-chain settlement.
	_, err = client.Transfer(ctx, "0xRecipientAddress...", "usdc", decimal.NewFromInt(50))
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Transfer completed off-chain")
}

Client Configuration

The `NewClient` function accepts variadic `ClientOption` functions to customize behavior:

  • `WithBlockchainRPC(chainID, url)`: Registers an RPC endpoint for on-chain settlement.
  • `WithHandshakeTimeout(duration)`: Sets the timeout for the initial WebSocket handshake.
  • `WithPingInterval(duration)`: Sets the interval for WebSocket ping/pong keepalives.
  • `WithErrorHandler(func(error))`: Sets a callback for handling background connection errors.

Error Handling

The SDK methods return standard Go errors. Common errors to check for include connection issues, insufficient balances, or invalid state transitions. Errors from RPC calls often contain detailed messages from the Clearnode server.

Index

Constants

View Source
const (
	// DefaultChallengePeriod is the default challenge period for channels (1 day in seconds)
	DefaultChallengePeriod = 86400
)

Variables

View Source
var DefaultConfig = Config{
	HandshakeTimeout: 5 * time.Second,
	PingTimeout:      15 * time.Second,
	ErrorHandler:     defaultErrorHandler,
}

DefaultConfig returns the default configuration with sensible defaults.

Functions

This section is empty.

Types

type Client

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

Client provides a unified interface for interacting with Clearnode. It combines state-building operations (Deposit, Withdraw, Transfer) with a single Checkpoint method for blockchain settlement, plus low-level RPC access for advanced use cases.

The two-step pattern for blockchain operations:

  1. Build and co-sign the state off-chain (Deposit, Withdraw, CloseHomeChannel, etc.)
  2. Settle on-chain via Checkpoint

High-level example:

stateSigner, _ := sign.NewEthereumMsgSigner(privateKeyHex)
txSigner, _ := sign.NewEthereumRawSigner(privateKeyHex)
client, _ := sdk.NewClient(
    "wss://clearnode-sandbox.yellow.org/v1/ws",
    stateSigner,
    txSigner,
    sdk.WithBlockchainRPC(80002, "https://polygon-amoy.alchemy.com/v2/KEY"),
)
defer client.Close()

// Deposit: build state, then settle on-chain
state, _ := client.Deposit(ctx, 80002, "usdc", decimal.NewFromInt(100))
txHash, _ := client.Checkpoint(ctx, "usdc")

// Transfer: off-chain only, no Checkpoint needed for existing channels
state, _ = client.Transfer(ctx, "0xRecipient...", "usdc", decimal.NewFromInt(50))

// Low-level operations
config, _ := client.GetConfig(ctx)
balances, _ := client.GetBalances(ctx, walletAddress)

func NewClient

func NewClient(wsURL string, stateSigner core.ChannelSigner, rawSigner sign.Signer, opts ...Option) (*Client, error)

NewClient creates a new Clearnode client with both high-level and low-level methods. This is the recommended constructor for most use cases.

Parameters:

  • wsURL: WebSocket URL of the Clearnode server (e.g., "wss://clearnode-sandbox.yellow.org/v1/ws")
  • stateSigner: core.ChannelSigner for signing channel states (use sign.NewEthereumMsgSigner)
  • txSigner: sign.Signer for signing blockchain transactions (use sign.NewEthereumRawSigner)
  • opts: Optional configuration (WithBlockchainRPC, WithHandshakeTimeout, etc.)

Returns:

  • Configured Client ready for operations
  • Error if connection or initialization fails

Example:

stateSigner, _ := sign.NewEthereumMsgSigner(privateKeyHex)
txSigner, _ := sign.NewEthereumRawSigner(privateKeyHex)
client, err := sdk.NewClient(
    "wss://clearnode-sandbox.yellow.org/v1/ws",
    stateSigner,
    txSigner,
    sdk.WithBlockchainRPC(80002, "https://polygon-amoy.alchemy.com/v2/KEY"),
)

func (*Client) Acknowledge

func (c *Client) Acknowledge(ctx context.Context, asset string) (*core.State, error)

Acknowledge prepares an acknowledgement state for the given asset. This is used when a user receives a transfer but hasn't yet acknowledged the state, or to acknowledge channel creation without a deposit.

This method handles two scenarios automatically:

  1. If no channel exists: Creates a new channel with the acknowledgement transition
  2. If channel exists: Advances the state with an acknowledgement transition

The returned state is signed by both the user and the node.

Parameters:

  • ctx: Context for the operation
  • asset: The asset symbol to acknowledge (e.g., "usdc")

Returns:

  • The co-signed state with the acknowledgement transition applied
  • Error if the operation fails

Requirements:

  • Home blockchain must be set for the asset (use SetHomeBlockchain) when no channel exists

Example:

state, err := client.Acknowledge(ctx, "usdc")

func (*Client) ApproveSecurityToken

func (c *Client) ApproveSecurityToken(ctx context.Context, chainID uint64, amount decimal.Decimal) (string, error)

ApproveSecurityToken approves the Locking contract to spend tokens on behalf of the caller. This must be called before Lock Security Tokens.

Parameters:

  • ctx: Context for the operation
  • chainID: The blockchain network ID
  • amount: The amount of tokens to approve

Returns:

  • Transaction hash
  • Error if the operation fails

func (*Client) ApproveToken

func (c *Client) ApproveToken(ctx context.Context, chainID uint64, asset string, amount decimal.Decimal) (string, error)

ApproveToken approves the ChannelHub contract to spend tokens on behalf of the user. This is required before depositing ERC-20 tokens. Native tokens (e.g., ETH) do not require approval and will return an error if attempted.

Parameters:

  • ctx: Context for the operation
  • chainID: The blockchain network ID (e.g., 11155111 for Sepolia)
  • asset: The asset symbol to approve (e.g., "usdc")
  • amount: The amount to approve for spending

Returns:

  • Transaction hash of the approval transaction
  • Error if the operation fails or the asset is a native token

func (*Client) CancelSecurityTokensWithdrawal

func (c *Client) CancelSecurityTokensWithdrawal(ctx context.Context, blockchainID uint64) (string, error)

CancelSecurityTokensWithdrawal re-locks tokens that are currently in the unlocking state, cancelling the pending unlock and returning them to the locked state.

Parameters:

  • ctx: Context for the operation
  • blockchainID: The blockchain network ID

Returns:

  • Transaction hash
  • Error if the operation fails

func (*Client) Challenge

func (c *Client) Challenge(ctx context.Context, state core.State) (string, error)

Challenge submits an on-chain challenge for a channel using a co-signed state. The state must have both user and node signatures, which are validated before the challenge transaction is submitted.

A challenge initiates a dispute period on-chain. If the counterparty does not respond with a higher-versioned state before the challenge period expires, the channel can be closed with the challenged state.

Parameters:

  • ctx: Context for the operation
  • state: A co-signed state (both UserSig and NodeSig must be present)

Returns:

  • Transaction hash of the on-chain challenge transaction
  • Error if validation or submission fails

Requirements:

  • Blockchain RPC must be configured for the chain (use WithBlockchainRPC)
  • State must have both user and node signatures
  • State must have a HomeChannelID

Example:

state, err := client.GetLatestState(ctx, wallet, "usdc", true)
txHash, err := client.Challenge(ctx, *state)
fmt.Printf("Challenge transaction: %s\n", txHash)

func (*Client) Checkpoint

func (c *Client) Checkpoint(ctx context.Context, asset string) (string, error)

Checkpoint executes the blockchain transaction for the latest signed state. It fetches the latest co-signed state and, based on the transition type and on-chain channel status, calls the appropriate blockchain method.

This is the only method that interacts with the blockchain. It should be called after any state-building method (Deposit, Withdraw, CloseHomeChannel, etc.) to settle the state on-chain. It can also be used as a recovery mechanism if a previous blockchain transaction failed (e.g., due to gas issues or network problems).

Blockchain method mapping:

  • Channel not yet on-chain (status Void): Creates the channel via blockchainClient.Create
  • HomeDeposit/HomeWithdrawal on existing channel: Checkpoints via blockchainClient.Checkpoint
  • Finalize: Closes the channel via blockchainClient.Close

Parameters:

  • ctx: Context for the operation
  • asset: The asset symbol (e.g., "usdc")

Returns:

  • Transaction hash of the blockchain transaction
  • Error if the operation fails or no blockchain operation is needed

Requirements:

  • Blockchain RPC must be configured for the chain (use WithBlockchainRPC)
  • A co-signed state must exist (call Deposit, Withdraw, etc. first)

Example:

state, err := client.Deposit(ctx, 80002, "usdc", decimal.NewFromInt(100))
txHash, err := client.Checkpoint(ctx, "usdc")
fmt.Printf("On-chain transaction: %s\n", txHash)

func (*Client) Close

func (c *Client) Close() error

Close cleanly shuts down the client connection. It's recommended to defer this call after creating the client.

Example:

client, err := NewClient(...)
if err != nil {
    log.Fatal(err)
}
defer client.Close()

func (*Client) CloseHomeChannel

func (c *Client) CloseHomeChannel(ctx context.Context, asset string) (*core.State, error)

CloseHomeChannel prepares a finalize state to close the user's channel for a specific asset. This creates a final state with zero user balance and submits it to the node.

The returned state is signed by both the user and the node, but has not yet been submitted to the blockchain. Use Checkpoint to execute the on-chain close.

Parameters:

  • ctx: Context for the operation
  • asset: The asset symbol to close (e.g., "usdc")

Returns:

  • The co-signed finalize state ready for on-chain close
  • Error if the operation fails

Errors:

  • Returns error if no channel exists for the asset
  • Returns error if state signing or submission fails

Example:

state, err := client.CloseHomeChannel(ctx, "usdc")
txHash, err := client.Checkpoint(ctx, "usdc")
fmt.Printf("Close transaction: %s\n", txHash)

func (*Client) CreateAppSession

func (c *Client) CreateAppSession(ctx context.Context, definition app.AppDefinitionV1, sessionData string, quorumSigs []string, opts ...CreateAppSessionOptions) (string, string, string, error)

CreateAppSession creates a new application session between participants.

Parameters:

  • definition: The app definition with participants, quorum, application ID
  • sessionData: Optional JSON stringified session data
  • quorumSigs: Participant signatures for the app session creation
  • opts: Optional parameters (owner signature for apps requiring approval)

Returns:

  • AppSessionID of the created session
  • Initial version of the session
  • Status of the session
  • Error if the request fails

Example:

def := app.AppDefinitionV1{
    Application: "chess-v1",
    Participants: []app.AppParticipantV1{...},
    Quorum: 2,
    Nonce: 1,
}
sessionID, version, status, err := client.CreateAppSession(ctx, def, "{}", []string{"sig1", "sig2"})

func (*Client) Deposit

func (c *Client) Deposit(ctx context.Context, blockchainID uint64, asset string, amount decimal.Decimal) (*core.State, error)

Deposit prepares a deposit state for the user's channel. This method handles two scenarios automatically:

  1. If no channel exists: Creates a new channel with the initial deposit
  2. If channel exists: Advances the state with a deposit transition

The returned state is signed by both the user and the node, but has not yet been submitted to the blockchain. Use Checkpoint to execute the on-chain transaction.

Parameters:

  • ctx: Context for the operation
  • blockchainID: The blockchain network ID (e.g., 80002 for Polygon Amoy)
  • asset: The asset symbol to deposit (e.g., "usdc")
  • amount: The amount to deposit

Returns:

  • The co-signed state ready for on-chain checkpoint
  • Error if the operation fails

Example:

state, err := client.Deposit(ctx, 80002, "usdc", decimal.NewFromInt(100))
txHash, err := client.Checkpoint(ctx, "usdc")
fmt.Printf("Deposit transaction: %s\n", txHash)

func (*Client) EscrowSecurityTokens

func (c *Client) EscrowSecurityTokens(ctx context.Context, targetWalletAddress string, blockchainID uint64, amount decimal.Decimal) (string, error)

EscrowSecurityTokens locks tokens into the Locking contract on the specified blockchain. The tokens are locked for the caller's own address. Before calling this method, you must approve the Locking to spend your tokens using ApproveSecurityToken.

Parameters:

  • ctx: Context for the operation
  • destinationWalletAddress: The Ethereum address to lock tokens for
  • blockchainID: The blockchain network ID
  • amount: The amount of tokens to lock (in human-readable decimals, e.g., 100.5 USDC)

Returns:

  • Transaction hash
  • Error if the operation fails

func (*Client) GetActionAllowances

func (c *Client) GetActionAllowances(ctx context.Context, wallet string) ([]core.ActionAllowance, error)

GetActionAllowances retrieves the action allowances for a user based on their staking level.

Parameters:

  • wallet: The user's wallet address

Returns:

  • Slice of ActionAllowance containing allowance information per gated action
  • Error if the request fails

func (*Client) GetAppDefinition

func (c *Client) GetAppDefinition(ctx context.Context, appSessionID string) (*app.AppDefinitionV1, error)

GetAppDefinition retrieves the definition for a specific app session.

Parameters:

  • appSessionID: The application session ID

Returns:

  • app.AppDefinitionV1 with participants, quorum, and application info
  • Error if the request fails

Example:

def, err := client.GetAppDefinition(ctx, "session123")
fmt.Printf("App: %s, Quorum: %d\n", def.Application, def.Quorum)

func (*Client) GetAppSessions

GetAppSessions retrieves application sessions with optional filtering.

Parameters:

  • opts: Optional filters (pass nil for no filters)

Returns:

  • Slice of AppSession
  • core.PaginationMetadata with pagination information
  • Error if the request fails

Example:

sessions, meta, err := client.GetAppSessions(ctx, nil)
for _, session := range sessions {
    fmt.Printf("Session %s: %d participants\n", session.AppSessionID, len(session.Participants))
}

func (*Client) GetApps

GetApps retrieves registered applications with optional filtering.

Parameters:

  • opts: Optional filters (pass nil for no filters)

Returns:

  • Slice of AppInfoV1 with application information
  • core.PaginationMetadata with pagination information
  • Error if the request fails

Example:

apps, meta, err := client.GetApps(ctx, nil)
for _, a := range apps {
    fmt.Printf("App %s owned by %s\n", a.App.ID, a.App.OwnerWallet)
}

func (*Client) GetAssets

func (c *Client) GetAssets(ctx context.Context, blockchainID *uint64) ([]core.Asset, error)

GetAssets retrieves all supported assets with optional blockchain filter.

Parameters:

  • blockchainID: Optional blockchain ID to filter assets (pass nil for all assets)

Returns:

  • Slice of Asset containing asset information and token implementations
  • Error if the request fails

Example:

assets, err := client.GetAssets(ctx, nil)
for _, asset := range assets {
    fmt.Printf("%s (%s): %d tokens\n", asset.Name, asset.Symbol, len(asset.Tokens))
}

func (*Client) GetBalances

func (c *Client) GetBalances(ctx context.Context, wallet string) ([]core.BalanceEntry, error)

GetBalances retrieves the balance information for a user.

Parameters:

  • wallet: The user's wallet address

Returns:

  • Slice of Balance containing asset balances
  • Error if the request fails

Example:

balances, err := client.GetBalances(ctx, "0x1234567890abcdef...")
for _, balance := range balances {
    fmt.Printf("%s: %s\n", balance.Asset, balance.Balance)
}

func (*Client) GetBlockchains

func (c *Client) GetBlockchains(ctx context.Context) ([]core.Blockchain, error)

GetBlockchains retrieves the list of supported blockchain networks. This is a convenience method that calls GetConfig and extracts the blockchains list.

Returns:

  • Slice of Blockchain containing name, chain ID, and contract address for each network
  • Error if the request fails

Example:

blockchains, err := client.GetBlockchains(ctx)
for _, bc := range blockchains {
    fmt.Printf("%s: %s\n", bc.Name, bc.ChannelHubAddress)
}

func (*Client) GetConfig

func (c *Client) GetConfig(ctx context.Context) (*core.NodeConfig, error)

GetConfig retrieves the clearnode configuration including node identity and supported blockchains.

Returns:

  • NodeConfig containing the node address, version, and list of supported blockchain networks
  • Error if the request fails

Example:

config, err := client.GetConfig(ctx)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Node: %s (v%s)\n", config.NodeAddress, config.NodeVersion)

func (*Client) GetEscrowChannel

func (c *Client) GetEscrowChannel(ctx context.Context, escrowChannelID string) (*core.Channel, error)

GetEscrowChannel retrieves escrow channel information for a specific channel ID.

Parameters:

  • escrowChannelID: The escrow channel ID to query

Returns:

  • Channel information for the escrow channel
  • Error if the request fails

Example:

channel, err := client.GetEscrowChannel(ctx, "0x1234...")
fmt.Printf("Escrow Channel: %s (Version: %d)\n", channel.ChannelID, channel.StateVersion)

func (*Client) GetHomeChannel

func (c *Client) GetHomeChannel(ctx context.Context, wallet, asset string) (*core.Channel, error)

GetHomeChannel retrieves home channel information for a user's asset.

Parameters:

  • wallet: The user's wallet address
  • asset: The asset symbol

Returns:

  • Channel information for the home channel
  • Error if the request fails

Example:

channel, err := client.GetHomeChannel(ctx, "0x1234...", "usdc")
fmt.Printf("Home Channel: %s (Version: %d)\n", channel.ChannelID, channel.StateVersion)

func (*Client) GetLastAppKeyStates

func (c *Client) GetLastAppKeyStates(ctx context.Context, userAddress string, opts *GetLastKeyStatesOptions) ([]app.AppSessionKeyStateV1, error)

GetLastAppKeyStates retrieves the latest session key states for a user.

Parameters:

  • userAddress: The user's wallet address
  • opts: Optional filters (pass nil for no filters)

Returns:

  • Slice of AppSessionKeyStateV1 with the latest non-expired session key states
  • Error if the request fails

Example:

states, err := client.GetLastAppKeyStates(ctx, "0x1234...", nil)
for _, state := range states {
    fmt.Printf("Session key %s expires at %s\n", state.SessionKey, state.ExpiresAt)
}

func (*Client) GetLastChannelKeyStates

func (c *Client) GetLastChannelKeyStates(ctx context.Context, userAddress string, opts *GetLastChannelKeyStatesOptions) ([]core.ChannelSessionKeyStateV1, error)

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

Parameters:

  • userAddress: The user's wallet address
  • opts: Optional filters (pass nil for no filters)

Returns:

  • Slice of ChannelSessionKeyStateV1 with the latest non-expired session key states
  • Error if the request fails

Example:

states, err := client.GetLastChannelKeyStates(ctx, "0x1234...", nil)
for _, state := range states {
    fmt.Printf("Session key %s expires at %s\n", state.SessionKey, state.ExpiresAt)
}

func (*Client) GetLatestState

func (c *Client) GetLatestState(ctx context.Context, wallet, asset string, onlySigned bool) (*core.State, error)

GetLatestState retrieves the latest state for a user's asset.

Parameters:

  • wallet: The user's wallet address
  • asset: The asset symbol (e.g., "usdc")
  • onlySigned: If true, returns only the latest signed state

Returns:

  • core.State containing all state information
  • Error if the request fails

Example:

state, err := client.GetLatestState(ctx, "0x1234...", "usdc", false)
fmt.Printf("State Version: %d, Balance: %s\n", state.Version, state.HomeLedger.UserBalance)

func (*Client) GetLockedBalance

func (c *Client) GetLockedBalance(ctx context.Context, chainID uint64, wallet string) (decimal.Decimal, error)

GetLockedBalance returns the locked balance of a user in the Locking contract.

Parameters:

  • ctx: Context for the operation
  • chainID: The blockchain network ID
  • wallet: The Ethereum address to check

Returns:

  • The locked balance as a decimal (adjusted for token decimals)
  • Error if the query fails

func (*Client) GetOnChainBalance

func (c *Client) GetOnChainBalance(ctx context.Context, chainID uint64, asset string, wallet string) (decimal.Decimal, error)

GetOnChainBalance queries the on-chain token balance (ERC-20 or native ETH) for a wallet on a specific blockchain.

Parameters:

  • ctx: Context for the operation
  • chainID: The blockchain ID to query (e.g., 80002 for Polygon Amoy)
  • asset: The asset symbol (e.g., "usdc", "weth")
  • wallet: The Ethereum address to check the balance for

Returns:

  • The token balance as a decimal (already adjusted for token decimals)
  • Error if the query fails

Requirements:

  • Blockchain RPC must be configured for the chain (use WithBlockchainRPC)

func (*Client) GetTransactions

func (c *Client) GetTransactions(ctx context.Context, wallet string, opts *GetTransactionsOptions) ([]core.Transaction, core.PaginationMetadata, error)

GetTransactions retrieves transaction history for a user with optional filtering.

Parameters:

  • wallet: The user's wallet address
  • opts: Optional filters (pass nil for no filters)

Returns:

  • Slice of Transaction
  • core.PaginationMetadata with pagination information
  • Error if the request fails

Example:

txs, meta, err := client.GetTransactions(ctx, "0x1234...", nil)
for _, tx := range txs {
    fmt.Printf("%s: %s → %s (%s %s)\n", tx.TxType, tx.FromAccount, tx.ToAccount, tx.Amount, tx.Asset)
}

func (*Client) GetUserAddress

func (c *Client) GetUserAddress() string

GetUserAddress returns the Ethereum address associated with the signer. This is useful for identifying the current user's wallet address.

func (*Client) InitiateSecurityTokensWithdrawal

func (c *Client) InitiateSecurityTokensWithdrawal(ctx context.Context, blockchainID uint64) (string, error)

InitiateSecurityTokensWithdrawal initiates the unlock process for locked tokens in the Locking contract. After the unlock period elapses, Withdraw Security Tokens can be called to retrieve the tokens.

Parameters:

  • ctx: Context for the operation
  • blockchainID: The blockchain network ID

Returns:

  • Transaction hash
  • Error if the operation fails

func (*Client) Ping

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

Ping checks connectivity to the clearnode server. This is useful for health checks and verifying the connection is active.

Example:

if err := client.Ping(ctx); err != nil {
    log.Printf("Server is unreachable: %v", err)
}

func (*Client) RebalanceAppSessions

func (c *Client) RebalanceAppSessions(ctx context.Context, signedUpdates []app.SignedAppStateUpdateV1) (string, error)

RebalanceAppSessions rebalances multiple application sessions atomically.

This method performs atomic rebalancing across multiple app sessions, ensuring that funds are redistributed consistently without the risk of partial updates.

Parameters:

  • signedUpdates: Slice of signed app state updates to apply atomically

Returns:

  • BatchID for tracking the rebalancing operation
  • Error if the request fails

Example:

updates := []app.SignedAppStateUpdateV1{...}
batchID, err := client.RebalanceAppSessions(ctx, updates)
fmt.Printf("Rebalance batch ID: %s\n", batchID)

func (*Client) RegisterApp

func (c *Client) RegisterApp(ctx context.Context, appID string, metadata string, creationApprovalNotRequired bool) error

RegisterApp registers a new application in the app registry. Currently only version 1 (creation) is supported.

The method builds the app definition from the provided parameters, using the client's signer address as the owner wallet and version 1. It then packs and signs the definition automatically.

Session key signers are not allowed to perform this action; the main wallet signer must be used.

Parameters:

  • appID: The application identifier
  • metadata: The application metadata
  • creationApprovalNotRequired: Whether sessions can be created without owner approval

Returns:

  • Error if the request fails

Example:

err := client.RegisterApp(ctx, "my-app", `{"name": "My App"}`, false)

func (*Client) SetHomeBlockchain

func (c *Client) SetHomeBlockchain(asset string, blockchainId uint64) error

SetHomeBlockchain configures the primary blockchain network for a specific asset. This is required for operations like Transfer which may trigger channel creation but do not accept a blockchain ID as a parameter.

Validation:

  • Checks if the asset is actually supported on the specified blockchain.
  • Verifies that a home blockchain hasn't already been set for this asset.

Constraints:

  • This mapping is immutable once set for the client instance.
  • To move an asset to a different blockchain, use the Migrate() method instead.

Parameters:

  • asset: The asset symbol (e.g., "usdc")
  • blockchainId: The chain ID to associate with the asset (e.g., 80002)

Example:

// Set USDC to settle on Polygon Amoy
if err := client.SetHomeBlockchain("usdc", 80002); err != nil {
    log.Fatal(err)
}

func (*Client) SignChannelSessionKeyState

func (c *Client) SignChannelSessionKeyState(state core.ChannelSessionKeyStateV1) (string, error)

SignChannelSessionKeyState signs a channel session key state using the client's state signer. This creates a properly formatted signature that can be set on the state's UserSig field before submitting via SubmitChannelSessionKeyState.

Parameters:

  • state: The channel session key state to sign (UserSig field is excluded from signing)

Returns:

  • The hex-encoded signature string
  • Error if signing fails

Example:

state := core.ChannelSessionKeyStateV1{
    UserAddress: client.GetUserAddress(),
    SessionKey:  "0xabcd...",
    Version:     1,
    Assets:      []string{"usdc"},
    ExpiresAt:   time.Now().Add(24 * time.Hour),
}
sig, err := client.SignChannelSessionKeyState(state)
state.UserSig = sig
err = client.SubmitChannelSessionKeyState(ctx, state)

func (*Client) SignSessionKeyState

func (c *Client) SignSessionKeyState(state app.AppSessionKeyStateV1) (string, error)

SignSessionKeyState signs a session key state using the client's state signer. This creates a properly formatted signature that can be set on the state's UserSig field before submitting via SubmitSessionKeyState.

Parameters:

  • state: The session key state to sign (UserSig field is excluded from signing)

Returns:

  • The hex-encoded signature string
  • Error if signing fails

Example:

state := app.AppSessionKeyStateV1{
    UserAddress:    client.GetUserAddress(),
    SessionKey:     "0xabcd...",
    Version:        1,
    ApplicationIDs: []string{},
    AppSessionIDs:  []string{},
    ExpiresAt:      time.Now().Add(24 * time.Hour),
}
sig, err := client.SignSessionKeyState(state)
state.UserSig = sig
err = client.SubmitSessionKeyState(ctx, state)

func (*Client) SignState

func (c *Client) SignState(state *core.State) (string, error)

SignState signs a channel state by packing it, hashing it, and signing the hash. Returns the signature as a hex-encoded string (with 0x prefix).

This is a low-level method exposed for advanced users who want to manually construct and sign states. Most users should use the high-level methods like Transfer, Deposit, and Withdraw instead.

func (*Client) SubmitAppSessionDeposit

func (c *Client) SubmitAppSessionDeposit(ctx context.Context, appStateUpdate app.AppStateUpdateV1, quorumSigs []string, asset string, depositAmount decimal.Decimal) (string, error)

SubmitAppSessionDeposit submits a deposit to an app session. This updates both the app session state and the user's channel state.

Parameters:

  • appStateUpdate: The app state update with deposit intent
  • quorumSigs: Participant signatures for the app state update
  • userState: The user's updated channel state

Returns:

  • Node's signature for the state
  • Error if the request fails

Example:

appUpdate := app.AppStateUpdateV1{
    AppSessionID: "session123",
    Intent: app.AppStateUpdateIntentDeposit,
    Version: 2,
    Allocations: []app.AppAllocationV1{...},
}
nodeSig, err := client.SubmitAppSessionDeposit(ctx, appUpdate, []string{"sig1"}, userState)

func (*Client) SubmitAppSessionKeyState

func (c *Client) SubmitAppSessionKeyState(ctx context.Context, state app.AppSessionKeyStateV1) error

SubmitAppSessionKeyState submits a session key state for registration or update. The state must be signed by the user's wallet to authorize the session key delegation.

Parameters:

  • state: The session key state containing delegation information

Returns:

  • Error if the request fails

Example:

state := app.AppSessionKeyStateV1{
    UserAddress:    "0x1234...",
    SessionKey:     "0xabcd...",
    Version:        1,
    ApplicationIDs: []string{"app1"},
    AppSessionIDs:  []string{},
    ExpiresAt:      time.Now().Add(24 * time.Hour),
    UserSig:        "0x...",
}
err := client.SubmitAppSessionKeyState(ctx, state)

func (*Client) SubmitAppState

func (c *Client) SubmitAppState(ctx context.Context, appStateUpdate app.AppStateUpdateV1, quorumSigs []string) error

SubmitAppState submits an app session state update. This method handles operate, withdraw, and close intents. For deposits, use SubmitAppSessionDeposit instead.

Parameters:

  • appStateUpdate: The app state update (intent: operate, withdraw, or close)
  • quorumSigs: Participant signatures for the app state update

Returns:

  • Error if the request fails

Example:

appUpdate := app.AppStateUpdateV1{
    AppSessionID: "session123",
    Intent: app.AppStateUpdateIntentOperate,
    Version: 3,
    Allocations: []app.AppAllocationV1{...},
}
err := client.SubmitAppState(ctx, appUpdate, []string{"sig1", "sig2"})

func (*Client) SubmitChannelSessionKeyState

func (c *Client) SubmitChannelSessionKeyState(ctx context.Context, state core.ChannelSessionKeyStateV1) error

SubmitChannelSessionKeyState submits a channel session key state for registration or update. The state must be signed by the user's wallet to authorize the session key delegation.

Parameters:

  • state: The channel session key state containing delegation information

Returns:

  • Error if the request fails

Example:

state := core.ChannelSessionKeyStateV1{
    UserAddress: "0x1234...",
    SessionKey:  "0xabcd...",
    Version:     1,
    Assets:      []string{"usdc", "weth"},
    ExpiresAt:   time.Now().Add(24 * time.Hour),
    UserSig:     "0x...",
}
err := client.SubmitChannelSessionKeyState(ctx, state)

func (*Client) Transfer

func (c *Client) Transfer(ctx context.Context, recipientWallet string, asset string, amount decimal.Decimal) (*core.State, error)

Transfer prepares a transfer state to send funds to another wallet address. This method handles two scenarios automatically:

  1. If no channel exists: Creates a new channel with the transfer transition
  2. If channel exists: Advances the state with a transfer send transition

The returned state is signed by both the user and the node. For existing channels, no blockchain interaction is needed. For new channels, use Checkpoint to create the channel on-chain.

Parameters:

  • ctx: Context for the operation
  • recipientWallet: The recipient's wallet address (e.g., "0x1234...")
  • asset: The asset symbol to transfer (e.g., "usdc")
  • amount: The amount to transfer

Returns:

  • The co-signed state with the transfer transition applied
  • Error if the operation fails

Example:

state, err := client.Transfer(ctx, "0xRecipient...", "usdc", decimal.NewFromInt(50))
fmt.Printf("Transfer tx ID: %s\n", state.Transition.TxID)

func (*Client) WaitCh

func (c *Client) WaitCh() <-chan struct{}

WaitCh returns a channel that closes when the connection is lost or closed. This is useful for monitoring connection health in long-running applications.

Example:

go func() {
    <-client.WaitCh()
    log.Println("Connection closed")
}()

func (*Client) Withdraw

func (c *Client) Withdraw(ctx context.Context, blockchainID uint64, asset string, amount decimal.Decimal) (*core.State, error)

Withdraw prepares a withdrawal state to remove funds from the user's channel. This operation handles two scenarios automatically:

  1. If no channel exists: Creates a new channel with the withdrawal transition
  2. If channel exists: Advances the state with a withdrawal transition

The returned state is signed by both the user and the node, but has not yet been submitted to the blockchain. Use Checkpoint to execute the on-chain transaction.

Parameters:

  • ctx: Context for the operation
  • blockchainID: The blockchain network ID (e.g., 80002 for Polygon Amoy)
  • asset: The asset symbol to withdraw (e.g., "usdc")
  • amount: The amount to withdraw

Returns:

  • The co-signed state ready for on-chain checkpoint
  • Error if the operation fails

Example:

state, err := client.Withdraw(ctx, 80002, "usdc", decimal.NewFromInt(25))
txHash, err := client.Checkpoint(ctx, "usdc")
fmt.Printf("Withdrawal transaction: %s\n", txHash)

func (*Client) WithdrawSecurityTokens

func (c *Client) WithdrawSecurityTokens(ctx context.Context, blockchainID uint64, destinationWalletAddress string) (string, error)

WithdrawSecurityTokens withdraws unlocked tokens from the Locking contract to the specified destination. Can only be called after the unlock period has fully elapsed.

Parameters:

  • ctx: Context for the operation
  • blockchainID: The blockchain network ID
  • destinationWalletAddress: The Ethereum address to receive the withdrawn tokens

Returns:

  • Transaction hash
  • Error if the operation fails

type Config

type Config struct {
	// URL is the WebSocket URL of the clearnode server
	URL string

	// HandshakeTimeout is the maximum time to wait for initial connection
	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 detect dead clients.
	PingTimeout time.Duration

	// ErrorHandler is called when connection errors occur
	ErrorHandler func(error)

	// BlockchainRPCs maps blockchain IDs to their RPC endpoints
	// Used by SDKClient for on-chain operations
	BlockchainRPCs map[uint64]string
}

Config holds the configuration options for the Clearnode client.

type CreateAppSessionOptions

type CreateAppSessionOptions struct {
	// OwnerSig is the app owner's signature approving session creation.
	// Required when the app's CreationApprovalNotRequired is false.
	OwnerSig string
}

CreateAppSessionOptions contains optional parameters for CreateAppSession.

type GetAppSessionsOptions

type GetAppSessionsOptions struct {
	// AppSessionID filters by application session ID
	AppSessionID *string

	// Participant filters by participant wallet address
	Participant *string

	// Status filters by status ("open" or "closed")
	Status *string

	// Pagination parameters
	Pagination *core.PaginationParams
}

GetAppSessionsOptions contains optional filters for GetAppSessions.

type GetAppsOptions

type GetAppsOptions struct {
	// AppID filters by application ID
	AppID *string

	// OwnerWallet filters by owner wallet address
	OwnerWallet *string

	// Pagination parameters
	Pagination *core.PaginationParams
}

GetAppsOptions contains optional filters for GetApps.

type GetLastChannelKeyStatesOptions

type GetLastChannelKeyStatesOptions struct {
	// SessionKey filters by a specific session key address
	SessionKey *string
}

GetLastChannelKeyStatesOptions contains optional filters for GetLastChannelKeyStates.

type GetLastKeyStatesOptions

type GetLastKeyStatesOptions struct {
	// SessionKey filters by a specific session key address
	SessionKey *string
}

GetLastKeyStatesOptions contains optional filters for GetLastKeyStates.

type GetTransactionsOptions

type GetTransactionsOptions struct {
	// Asset filters by asset symbol
	Asset *string

	// Pagination parameters
	Pagination *core.PaginationParams
}

GetTransactionsOptions contains optional filters for GetTransactions.

type Option

type Option func(*Config)

Option is a functional option for configuring the Client.

func WithBlockchainRPC

func WithBlockchainRPC(chainID uint64, rpcURL string) Option

WithBlockchainRPC returns an Option that configures a blockchain RPC client for a specific chain. This is required for the Checkpoint method which settles states on-chain.

Parameters:

Example:

client, err := sdk.NewClient(
    wsURL,
    stateSigner,
    txSigner,
    sdk.WithBlockchainRPC(80002, "https://polygon-amoy.alchemy.com/v2/KEY"),
    sdk.WithBlockchainRPC(84532, "https://base-sepolia.alchemy.com/v2/KEY"),
)

func WithErrorHandler

func WithErrorHandler(fn func(error)) Option

WithErrorHandler sets a custom error handler for connection errors. The handler is called when the connection encounters an error or is closed.

func WithHandshakeTimeout

func WithHandshakeTimeout(d time.Duration) Option

WithHandshakeTimeout sets the maximum time to wait for initial connection.

func WithPingTimeout

func WithPingTimeout(d time.Duration) Option

WithPingTimeout sets how long to wait for a ping from the server before considering the connection dead.

Directories

Path Synopsis
examples
app_sessions command
challenge command

Jump to

Keyboard shortcuts

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