Instant Payments JavaScript API

No Comment Yet


1. Introduction

Welcome to the official documentation for the GRIDNET OS State-Less Channels sub-system and its associated Off-The-Chain Payment API. This document provides UI dApp developers with the necessary understanding and technical guidance to leverage this powerful mechanism for enabling fast, cost-effective, and scalable value transfer and incentivization within their decentralized applications.

1.1. Purpose: The Need for Off-Chain Solutions in GRIDNET OS

GRIDNET OS provides a robust platform for executing decentralized logic and managing state through its Decentralized State Machine (DSM). However, like all blockchain-based systems, direct on-chain transactions have inherent limitations that can hinder certain types of applications:

  • Scalability:

    The number of transactions per second (TPS) that can be processed directly on the main chain is finite. High-frequency operations can quickly saturate the network’s capacity.

  • Cost:

    Every transaction committed to the DSM consumes resources (ERG) for processing and storage. While designed to be efficient, on-chain operations can become prohibitively expensive for very small or frequent value exchanges (micropayments).

  • Speed & Latency:

    On-chain transactions require consensus and block finality, introducing latency. Real-time interactions demanding immediate confirmation or reward cannot solely rely on the main chain’s settlement time.

To overcome these challenges and unlock a wider range of possibilities for UI dApps, GRIDNET OS implements a sophisticated off-chain solution: the State-Less Channels system. This system is crucial for applications involving:

  • Micropayments:

    Enabling tiny value transfers for services, content access, or rewards where on-chain fees would be disproportionately high.

  • Incentivized Data Exchange:

    Efficiently rewarding peers for relaying data packets in real-time, essential for decentralized communication, storage, and services like the GRIDNET OS Web Proxy or WebRTC Swarms.

  • Real-time Rewards:

    Instantly rewarding user actions within games (like the Snake dApp) or other interactive applications without waiting for block confirmations.

1.2. Overview of the State-Less Channels System

The GRIDNET OS State-Less Channels system facilitates secure value transfer between parties without requiring every individual transfer to be recorded directly on the main blockchain (the DSM).

  • Analogy to Lightning Network:

    The goal is similar to layer-2 scaling solutions like Bitcoin’s Lightning Network – enabling faster, cheaper transactions off-chain. However, the underlying mechanics in GRIDNET OS are distinct. State-Less Channels do not rely on complex routed payment channels requiring intermediate node participation in the same way.

  • Core Idea: Secure Off-Chain Value Transfer Based on Pre-Funded Pools:

    The system operates on the principle of

    Multi-Dimensional Token Pools (M-DTPs)

    . These pools represent a store of value, initially funded via an on-chain sacrificial transaction and registered on the DSM. Value is then exchanged off-chain by securely revealing pre-images (hashes or “tokens”) derived from secrets associated with the pool’s dimensions (banks). Only the initial pool setup and the final “cashing out” of accumulated off-chain tokens require direct interaction with the DSM, significantly reducing on-chain load. The “State-Less” nature refers to the fact that complex channel state negotiation and management between peers are minimized compared to traditional state channels.

1.3. Key Benefits

1.4. GRIDNET OS’ Decentralized Incentivized SOA Paradigm

1.4.1. Introduction to Service-Oriented Architecture in GRIDNET OS

GRIDNET OS implements a unique approach to Service-Oriented Architecture (SOA) that fundamentally reimagines how distributed services can operate in a decentralized environment. Unlike traditional SOA implementations that rely on centralized service registries, orchestration, and payment systems, GRIDNET OS’ architecture distributes all aspects of service discovery, execution, and compensation across its peer-to-peer network.

Service-Oriented Architecture refers to a design pattern where applications are built from loosely coupled, independently deployable services that communicate through standardized interfaces. GRIDNET OS extends this concept by adding three critical dimensions:

  • Full Decentralization
    Services operate without central authorities or single points of failure
  • Built-in Incentivization
    Automatic, fine-grained compensation for service providers
  • Sybil-Resistant Economics
    Game-theoretical protection against network manipulation

1.4.2. Core Components of the Decentralized SOA

The GRIDNET OS Decentralized Incentivized SOA consists of several interconnected components:

Service Providers

Independent nodes that offer computational resources, storage capacity, bandwidth, or specialized functionality to the network. These can include:

  • Data relay nodes
  • Content delivery services
  • Computational services
  • Storage providers
  • Specialized application services (e.g., rendering, transcoding)

Service Consumers

Any participant in the GRIDNET OS ecosystem that needs to utilize services. This could be:

  • End-user applications (UI dApps)
  • Other service providers (service composition)
  • Automated agents or system components

Decentralized Service Registry

Unlike traditional SOA with centralized registries, GRIDNET OS implements service discovery through:

  • Distributed hash tables (DHTs)
  • Peer announcements via swarm protocols
  • On-chain service registration in the DSM
  • Path discovery mechanisms that identify capable service providers

State-Less Channels Incentivization Layer

This is where the State-Less Channels subsystem, as documented in this specification, plays a critical role. It provides:

  • Instantaneous micropayments for service utilization
  • Fine-grained compensation proportional to service quality and quantity
  • Economic incentives that maintain service availability and reliability
  • Sybil-resistant reward distribution through mathematical design

1.4.3. Incentivization Mechanism

Traditional SOA implementations typically rely on conventional payment systems or subscription models that operate out-of-band from the actual service calls. These systems face significant limitations in decentralized environments:

  • High transaction costs for micropayments
  • Lack of real-time compensation
  • Vulnerability to free-riding and Sybil attacks
  • Inability to handle high-frequency service invocations

GRIDNET OS overcomes these limitations through its State-Less Channels system:

Micropayment-Based Service Economy

Each service interaction can be individually compensated with minimal overhead:

  • A UI dApp consuming bandwidth from a WebRTC relay can issue Transmission Tokens for each data packet
  • A computational service can receive payment proportional to processing time or complexity
  • Content delivery nodes can be rewarded based on bytes transferred and delivery speed

Real-Time Incentives

Payments occur simultaneously with service delivery, creating immediate economic feedback:

  • Service providers receive compensation instantly, without waiting for transaction settlement
  • Quality of service directly correlates with economic reward
  • Resource allocation can dynamically adjust based on real-time incentives

Proportional Compensation

The amount of payment can be precisely calibrated to:

  • Value provided by the service
  • Resource consumption
  • Quality metrics (latency, throughput, availability)
  • Position in service paths or chains

1.4.4. SOA Implementation Examples

The Decentralized Incentivized SOA paradigm enables several key services within GRIDNET OS:

Decentralized Web Proxy

  • Service
    Access to web content through decentralized routing
  • Providers
    Nodes with internet connectivity willing to relay web requests
  • Incentivization
    Transmission Tokens issued per request or data volume
  • Benefits
    Censorship resistance, privacy enhancement, load distribution

WebRTC Swarms

  • Service
    Real-time media streaming and communication
  • Providers
    Nodes with sufficient bandwidth and network position
  • Incentivization
    Continuous micropayments based on relay quality and volume
  • Benefits
    Resilient communication, improved geographic distribution, automatic scaling

Distributed Storage System

  • Service
    Data persistence, backup, and retrieval
  • Providers
    Nodes with available disk space
  • Incentivization
    Payments for storage duration and retrieval speed
  • Benefits
    Redundancy without central planning, economic-driven availability

Computational Markets

  • Service
    Execution of computationally intensive tasks
  • Providers
    Nodes with spare CPU/GPU capacity
  • Incentivization
    Payment based on computational complexity and speed
  • Benefits
    Distributed load, specialized hardware utilization, market-driven pricing

1.4.5. Advantages Over Traditional SOA

GRIDNET OS’ Decentralized Incentivized SOA provides several key advantages:

Resilience and Redundancy

  • No single point of failure for service discovery or delivery
  • Automatic adaptation to node failures through economic incentives
  • Natural redundancy driven by reward mechanisms

Economic Efficiency

  • Services are priced according to actual resource costs
  • Reduced overhead compared to traditional payment systems
  • No need for complex billing, subscription, or account management

Dynamic Scaling

  • Service availability scales with demand through economic signals
  • Automatic load balancing through incentive distribution
  • Organic growth of service capacity in high-demand areas

Trustless Operation

  • No need to trust specific service providers
  • Service quality enforced through economic incentives rather than contracts
  • Decreased risk of service denial or censorship

1.4.6. Relation to State-Less Channels

The State-Less Channels system described in this documentation serves as the fundamental enabler of the Decentralized Incentivized SOA paradigm. By providing a mechanism for instant, trustless micropayments with minimal overhead, it creates the economic foundation upon which the entire service ecosystem operates.

Key aspects where State-Less Channels directly support the SOA paradigm:

  • Multi-Dimensionality
    The M-DTP structure with multiple banks allows service consumers to simultaneously incentivize multiple service providers using a single token pool
  • Instant Verification
    Services can verify payment validity immediately without on-chain confirmation
  • Path Assurance
    The PA1, PA2, and PA3 protocols ensure that incentives flow correctly through service chains
  • Scalability
    Off-chain payments enable high-frequency service invocations without blockchain congestion
  • Sybil Resistance
    Mathematical design prevents service providers from gaming the system through identity multiplication

Leveraging State-Less Channels via this API offers significant advantages:

  • Scalability & Throughput:

    Dramatically increases the potential volume of transactions/rewards that can occur between users and services, far exceeding on-chain TPS limits.

  • Reduced Transaction Costs:

    Amortizes the cost of on-chain operations. Instead of paying ERG for every small transfer, costs are primarily associated with the initial Token Pool creation and the final cash-out transaction.

  • Instantaneous (Off-Chain) Transactions:

    Off-chain token exchanges happen almost instantly between peers, ideal for real-time applications.

  • Enhanced Privacy:

    Individual off-chain transfers within a channel are not broadcast publicly across the DSM. Only the aggregated cash-out transaction is visible on-chain.

  • Sybil-Proof Incentivization:

    Builds upon the Sybil-proof mechanics detailed in [1], allowing for fair and secure rewarding of potentially unknown or numerous peers for minuscule actions without the overhead or security risks of individual on-chain micropayments.

1.5. Target Audience

This documentation is primarily intended for

UI dApp developers

building applications on the GRIDNET OS platform. It is particularly relevant for those whose dApps require:

  • High-frequency or low-value transactions.
  • Real-time reward mechanisms.
  • Incentivization for peer-to-peer data exchange or service provision.
  • Interaction with systems employing off-chain payments (e.g., integrated games, services).

1.6. Prerequisites

Before diving into this documentation, developers should possess:

  • A foundational understanding of

    GRIDNET OS concepts

    (DSM, IVR, DPT, VM Context, #GridScript basics).

  • Proficiency in modern

    JavaScript (ES6+)

    , including classes, Promises, and async/await.

  • Familiarity with

    event-driven programming paradigms

    , as interaction with the CVMContext and the State-Less Channels Manager is heavily reliant on event listeners and callbacks.


2. Core Concepts

This section delves into the fundamental ideas and data structures that underpin the GRIDNET OS State-Less Channels system. Understanding these concepts is essential for effectively utilizing the Off-The-Chain Payment API.

2.1. State-Less vs. State-Full Channels (Brief Comparison)

While various blockchain platforms offer “state channels” for off-chain interactions, GRIDNET OS employs a

State-Less Channel

  • State-Full Channels (e.g., Lightning Network):
    Typically require participants to maintain and constantly synchronize complex channel states (balances, commitments) directly with each other. Closing the channel often involves submitting the final agreed-upon state.
  • GRIDNET OS State-Less Channels:

    Minimize the need for direct, continuous state synchronization between peers during the off-chain phase. The “state” is primarily represented by the pre-funded Token Pool registered on the DSM and the sequence of revealed hashes (Tokens). Peers exchange Transmission Tokens, which act as verifiable claims against the pool. The final state reconciliation happens on-chain only during the cash-out process. This approach simplifies peer interaction and potentially enhances privacy during the off-chain phase.

2.2. Multi-Dimensional Token Pools (M-DTPs): The Foundation

The cornerstone of the State-Less Channels system is the

Multi-Dimensional Token Pool (M-DTP)

. It acts as a secure, on-chain registered escrow of value that enables off-chain payments.

  • Rationale for Multi-Dimensionality:

    A single-dimensional pool (a single hash chain) can only reliably serve one off-chain payment stream at a time. If Peer A is paying Peer B using a dimension, Peer A cannot safely start paying Peer C using the same dimension until Peer B has cashed out their received tokens on-chain. This creates a bottleneck. M-DTPs overcome this by providing multiple independent dimensions (Banks), allowing the pool owner to conduct simultaneous, independent off-chain payment streams with multiple different recipients using a single, pre-funded pool. This is crucial for scalability in scenarios like rewarding many data relays or game participants concurrently.

  • Creation:

    An M-DTP is typically created through a process involving:

    1. Sacrificial Transaction:

      The intended pool owner performs an on-chain transaction, effectively locking or “sacrificing” a specific amount of GBU/GNC. The transaction receipt serves as proof of this committed value.

    2. Off-Chain Generation:

      Using the sacrificial transaction receipt ID and desired parameters (number of dimensions, optionally value per token), the pool structure, including all internal hash chains, is generated off-chain. This critical step requires the owner’s secret

      MasterSeedHash

      and is usually performed securely by the GRIDNET Token mobile app via a QR Intent process.

    3. On-Chain Registration:

      The public data of the generated M-DTP (including the final hash for each dimension, total value, owner ID, unique Pool ID, etc., but excluding the MasterSeedHash) is then committed to the DSM.

  • On-Chain Representation:

    The registered M-DTP data is stored as a file (typically with a .pool extension) within the owner’s State Domain on the GRIDNET OS Decentralized File System (DFS). This file can be queried by anyone to verify the pool’s parameters and current on-chain state (e.g., bank usage depths).

  • Structure:

    Key components of an M-DTP include its unique Token Pool ID, the Owner’s ID, the total value committed, the number of dimensions (Banks), the value assigned to each individual token (usually calculated automatically based on total value, dimensions, and dimension depth), and the array of Banks, each containing its final hash and current usage depth as known by the DSM.

2.3. Token Pool Banks (Dimensions)

Each M-DTP is composed of one or more

Banks

, also referred to as

Dimensions

  • Independent Hash Chains:

    Each bank represents an independent, cryptographically generated hash chain.

  • Generating Hashes (Tokens):

    All hashes (tokens) within a bank are derived deterministically from a unique dimension seed hash (which is itself derived from the pool’s MasterSeedHash). This is achieved by repeatedly applying a cryptographic hash function (e.g., SHA256): Hash_i = Hash(Hash_{i-1}), starting from the dimension seed hash.

  • Ceiling Hashes (Final Hash):

    The last hash generated in the chain for a dimension (Hash_N) is called the ceiling or final hash. This value is stored publicly as part of the M-DTP data on the DSM and acts as the verification anchor for the entire chain within that dimension.

  • Tracking Usage Depth:

    The DSM maintains a record of how many tokens have been successfully cashed out from each bank. This ‘usage depth’ indicates the highest index ‘i’ for which Hash_i has been revealed and accepted on-chain. This is the primary mechanism preventing the same tokens (hashes) from being cashed out twice.

  • Bank Status:

    A bank can be ‘Active’ (has unspent tokens) or ‘Depleted’ (its usage depth has reached the maximum depth of the dimension).

2.4. Hash Chains and Tokens

  • Tokens as Preimages (Hashes):

    In this system, the “tokens” exchanged off-chain are the actual hash values (preimages) from the hash chain within a specific bank.

  • Releasing Tokens (Revealing Hashes):

    To spend value, the pool owner reveals hashes in reverse order of their generation. Revealing Hash_i requires knowledge of the original dimension seed hash (or a previously revealed Hash_{i-k}). Due to the nature of hash functions, revealing Hash_i automatically proves knowledge of (and implicitly reveals) all subsequent hashes Hash_{i+1} through Hash_N (the final hash).

  • Value Representation:

    The value of each single token/hash is uniform across all banks within a pool, determined during creation (e.g., 1 Atto, 1 GBU). The total value released is NumberOfRevealedHashes * ValuePerToken.

2.5. MasterSeedHash

  • The Single Secret:

    This is the high-entropy secret generated by the owner (typically via the mobile app) when creating the M-DTP. It is the only secret required to derive all dimension seed hashes and subsequently all individual tokens (hashes) within the entire pool.

  • Deriving Dimension Seeds:

    A deterministic function (e.g., hashing the MasterSeedHash concatenated with the dimension index) is used to generate the starting Seed Hash for each bank’s independent hash chain.

  • Security Implications:

    The MasterSeedHash

    must be kept absolutely secret

    by the pool owner. Its compromise allows an attacker to generate and potentially spend all remaining value in the pool. It should ideally reside only within a secure environment like the GRIDNET Token mobile app.

2.6. Transmission Tokens (TTs)

While the hashes themselves represent the value, the

Transmission Token (TT)

is the data structure used to communicate the release of this value off-chain. It packages the necessary information for the recipient to verify the claim and eventually cash it out on-chain.

  • Purpose:

    To provide proof of released value from a specific bank of a specific Token Pool, indicating the new state (usage depth) of that bank.

  • Structure:

    A TT (CTransmissionToken object in JS) contains:

    • Revealed Hash: The latest hash preimage being released in this transfer.
    • Revealed Hashes Count: How many new tokens this TT represents compared to the previously known state for this bank.
    • Bank Index: Identifies the specific dimension/bank within the M-DTP.
    • Bank Usage Depth: The new, total depth reached in this bank after releasing the tokens represented by this TT.
    • Token Pool ID: Identifies the parent M-DTP.
    • Value: The total GBU/Atto value represented by this specific TT.
    • (Optional) Recipient ID: Can specify the intended recipient.
    • (Optional) Signature: A signature from the Token Pool owner authenticating the TT.
  • Authenticated vs. Unauthenticated TTs:

    Unauthenticated TTs rely purely on the hash chain mathematics and on-chain state tracking for security against double-spending by the recipient. Authenticated TTs add a layer of non-repudiation and origin verification, crucial for certain applications or dispute resolution, and mandatory for “Bank Updates” (where the owner reveals hashes to their own web-session to enable spending).

2.7. Transit Pools

The term

Transit Pool

doesn’t represent a distinct, stored data structure in the same way as a Token Pool.

  • Concept:

    It refers to the cumulative value represented by a sequence of off-chain Transmission Tokens exchanged since the last on-chain cash-out for a specific bank.

  • On-Chain Representation:

    When cashing out, typically only the latest Transmission Token received needs to be submitted to the DSM via the xTTEx GridScript command. This single TT contains the final revealed hash and the total usage depth for that bank, implicitly representing the entire “transit pool” of value accumulated off-chain since the last settlement.

2.8. Cashing Out

This is the process of converting the off-chain value represented by Transmission Tokens back into on-chain GBU/GNC balance.

  • The Process:

    The recipient (or the CStateLessChannelsManager autonomously) submits the latest valid Transmission Token for a specific bank/pool to the DSM via an xTTEx GridScript instruction, usually packaged within a standard on-chain transaction.

  • On-Chain Verification:

    The DSM node executing the transaction verifies the TT against the on-chain state of the corresponding M-DTP file:

    1. Checks if the Token Pool ID exists and the pool is Active.
    2. Checks if the Bank Index is valid.
    3. Checks if the Bank Usage Depth in the TT is greater than the currently recorded depth for that bank (prevents replay/double-spend).
    4. Cryptographically verifies the hash chain segment by repeatedly hashing the Revealed Hash for Revealed Hashes Count times and checking if it matches the currently recorded final hash for that bank state.
    5. (If TT is authenticated) Verifies the signature against the Token Pool owner’s public key.
  • State Update:

    If verification succeeds, the DSM updates the bank’s usage depth in the M-DTP file on DFS and credits the Value specified in the TT to the designated recipient’s on-chain account balance.

  • Associated Costs:

    Executing the xTTEx command and the encompassing transaction incurs standard ERG costs on the DSM.

2.9. StateLessChannel Object (CStateLessChannel)

This JavaScript class serves as the primary high-level abstraction for UI dApp developers interacting with the off-chain payment system.

  • JavaScript Abstraction:

    It encapsulates the logic for managing interaction with a single Token Pool, hiding complexities like direct BER encoding/decoding or GridScript command formulation.

  • Relationship to On-Chain Data:

    Each CStateLessChannel instance is associated with a specific Token Pool ID. It maintains a local cache (mTokenPool) of the pool’s data, which needs to be periodically synchronized (synchronize()) with the state stored on the DSM/DFS.

  • Ingress vs. Outgress:

    The direction is determined relative to the local user interacting via the UI dApp:

    • Ingress Channel:

      Represents a pool owned by another party from which the local user receives payments/rewards (e.g., Snake game rewards). The dApp typically uses this to validate incoming TTs and initiate cash-outs.

    • Outgress Channel:

      Represents a pool owned by the local user used to send payments to others. The dApp uses this to generate and potentially deliver TTs.

  1. Architecture and Interaction Flow

Understanding how the different parts of GRIDNET OS interact to enable State-Less Channels is key to building robust UI dApps. This section outlines the primary components involved and the typical flow of information and control between them.

3. Architecture and Interaction Flow

Understanding how the different parts of GRIDNET OS interact to enable State-Less Channels is key to building robust UI dApps. This section outlines the primary components involved and the typical flow of information and control between them.

3.1. System Components Overview

The State-Less Channels sub-system involves a collaboration between several distinct components operating at different levels:

  • UI dApp (e.g., Wallet, Game):

    The user-facing application built using web technologies (HTML, CSS, JS) running within a CWindow instance. It initiates actions (like sending a payment or requesting a cash-out) and subscribes to events to update its state and display information (e.g., received tokens, channel balance). UI dApps only interact with the system via the CVMContext.

  • JavaScript VM Context (CVMContext):

    The central singleton object acting as the sole gateway between UI dApps and the underlying GRIDNET OS functionalities. It manages communication with Core Nodes, handles event dispatching, provides access to various managers (like the Channels Manager), and facilitates the execution of GridScript commands originating from dApps.

  • State-Less Channels Manager (CStateLessChannelsManager):

    A singleton service, accessible via CVMContext, responsible for the overall management of all State-Less Channel instances within the user’s session. It handles incoming network events related to channels, routes data to the appropriate channel objects, manages a local cache of known channels, performs autonomous tasks like synchronization and automatic cash-outs, and exposes the primary API for dApps to interact with the channel system.

  • State-Less Channel Objects (CStateLessChannel):

    JavaScript objects, managed by the CStateLessChannelsManager, each representing a single, specific off-chain payment channel linked to a unique Multi-Dimensional Token Pool ID. It encapsulates the logic for validating/generating Transmission Tokens, interacting with its cached CTokenPool data, and initiating requests for synchronization or cashing out.

  • Token Pool Objects (CTokenPool, CTokenPoolBank):

    JavaScript data structures representing the M-DTP and its individual dimensions (Banks) as loaded from the DSM or constructed locally. They contain the core cryptographic state (final hashes, usage depths) and logic for hash chain verification used by CStateLessChannel.

  • Transmission Token Objects (CTransmissionToken):

    JavaScript data structure representing the off-chain payment instrument, containing the revealed hash, value, bank details, etc.

  • GRIDNET Core Nodes:

    The distributed network nodes that maintain the Decentralized State Machine (DSM), execute #GridScript commands (like xTTEx for cashing out), manage the Decentralized File System (DFS) where Token Pool data is stored, and handle underlying network communication (UDT, WebSockets, etc.).

  • GRIDNET Token Mobile App:

    The user’s secure companion application. It holds sensitive keys (like the MasterSeedHash needed for pool generation), performs cryptographic operations (signing transactions, generating hashes/tokens securely), and interacts with Core Nodes via QR Intents and secure, often onion-routed, connections to authorize critical actions.

3.2. Interaction Diagram (High-Level)

(Conceptual Description – A visual diagram would accompany this in full documentation)

Imagine a layered architecture:

  1. UI Layer:

    The UI dApp presents information and captures user intent.

  2. API Gateway Layer:

    The CVMContext receives requests from the dApp and dispatches events back to it.

  3. Service Layer:

    The CStateLessChannelsManager resides here, accessed via CVMContext. It orchestrates channel operations.

  4. Object Layer:

    CStateLessChannel, CTokenPool, CTransmissionToken objects manage the state and logic for individual channels/tokens.

  5. Core Layer:

    GRIDNET Core Nodes execute commands and manage the persistent DSM/DFS state.

  6. Security Layer:

    The Mobile App handles sensitive key operations and authorizations.

Communication flows vertically (e.g., dApp -> CVMContext -> Manager) and horizontally (e.g., CVMContext <-> Core Node; Mobile App <-> Core Node). Events propagate upwards (Core -> CVMContext -> Manager -> Channel -> dApp).

3.3. Role of CVMContext

Within the State-Less Channels system, CVMContext acts as the essential intermediary and event bus:

  • Singleton Access Point:

    It’s the only way for a UI dApp to access the CStateLessChannelsManager (getChannelsManager()) and other OS services.

  • Event Dispatcher:

    It receives low-level events from Core Nodes (e.g., via the VM Meta-Data protocol containing new TTs or pool data, or via DFS message results) and dispatches them to registered listeners, including the CStateLessChannelsManager.

  • Processing GridScript Commands:

    It takes requests formulated by the Manager or Channel objects (often wrapped in CVMMetaGenerator objects) and sends them to the appropriate Core Node for execution using methods like processVMMetaDataKF. This is how cash-out (xTTEx) and pool synchronization (getPoolEx) commands are initiated.

3.4. Role of CStateLessChannelsManager

The Manager is the central coordinator for all off-chain payment activity:

  • Central Hub:

    Manages the lifecycle and collection of all active CStateLessChannel instances for the current user session.

  • Event Routing:

    Listens for relevant events from CVMContext (newVMMetaDataCallback, newDFSMsgCallback). It parses incoming data (e.g., deserializing TTs or Token Pools from BER encoding) and routes it to the correct CStateLessChannel object based on the Token Pool ID.

  • Autonomous Operations:

    Runs its own internal timer (controllerThreadF) to periodically trigger channel synchronization (syncChannels) and check conditions for automatic cash-outs (cashOutChannels) based on configured thresholds (mCashOutChannelAfterTimout, mCashOutChannelsAtValue).

  • Local Cache:

    Maintains the mChannels array, the primary list of known/managed channel objects.

  • API Provider:

    Exposes functions (like findChannelByID, syncAgentChannels) that UI dApps access through the CVMContext to interact with the channel system at a higher level.

3.5. Role of CStateLessChannel Objects

Each instance represents and manages a single channel:

  • Channel State:

    Holds the locally cached CTokenPool object representing the channel’s state (final hashes, usage depths, etc.) as last known.

  • Token Pool Interaction:

    Contains references to the underlying CTokenPool and CTokenPoolBank logic for calculations.

  • Core Logic:

    Implements the primary off-chain logic:

    • validateTT: Verifies incoming Transmission Tokens against the cached pool state.
    • getTTForPeer/getTTWorthValue: Generates new Transmission Tokens for sending payments (if it’s an Outgress channel).
  • Initiating Operations:

    Triggers requests via the Manager/CVMContext for:

    • synchronize(): To update its cached CTokenPool from the DSM/DFS.
    • cashOut(): To initiate the on-chain settlement process.

3.6. Interaction with the Decentralized State Machine (DSM)

The DSM and its associated DFS are the persistent, consensus-driven backend:

  • Storing Token Pool Data:

    Public M-DTP data (final hashes, total value, owner, ID, current bank depths) is stored as files within the DFS, typically under the owner’s State Domain (e.g., /OwnerID/TokenPools/PoolID.pool).

  • Executing Cash-Out Transactions:

    Core Nodes execute the xTTEx #GridScript command submitted in a transaction. This involves reading the relevant Token Pool file from DFS, performing the cryptographic verification of the submitted TT, updating the bank’s usage depth in the pool file, and crediting the recipient’s on-chain balance.

  • Reading Token Pool State:

    The getPoolEx #GridScript command reads the .pool file from DFS and returns its BER-encoded content, enabling synchronization.

3.7. Interaction with the Mobile App

The mobile app acts as the user’s secure hardware wallet and authorization device:

  • QR Intents:

    Facilitates secure communication for operations requiring the user’s private key or the secret MasterSeedHash.

  • Pool Generation:

    The computationally intensive and security-critical generation of M-DTP hash chains from the MasterSeedHash happens only within the mobile app in response to a genPool QR Intent. The app returns the disarmed (public) pool data.

  • MasterSeedHash Management:

    Securely stores and manages the user’s MasterSeedHash(es).

  • Signing:

    Signs critical on-chain transactions (like the one registering a new pool or potentially cash-out requests if configured) via QR Intents.

  • Providing “Bank Updates”:

    Can securely reveal specific hash preimages (packaged as authenticated TTs with isBankUpdate=true) to the user’s web session via QR Intents, allowing the web UI/dApp to spend pre-funded value from an Outgress channel without exposing the MasterSeedHash.

3.8. Event-Driven Communication Flow (Simplified Sequences)

  • Receiving a TT (e.g., Peer-to-Peer or Game Reward):

    1. TT arrives at a Core Node (e.g., via WebRTC Swarm or direct connection).
    2. Core Node may wrap it in VM Meta-Data and send it to the relevant CVMContext.
    3. CVMContext receives the VM Meta-Data message.
    4. CVMContext dispatches the event to its listeners, including CStateLessChannelsManager.
    5. Manager.newVMMetaDataCallback parses the message, identifies it as a TT/BankUpdate, deserializes the CTransmissionToken.
    6. Manager finds the corresponding CStateLessChannel object by Pool ID (creating one if necessary via onNewChannel after fetching pool data).
    7. Manager calls channel.validateTT (potentially updating the channel’s internal state).
    8. Manager raises the onTT and onChannelNewState events.
    9. CVMContext dispatches these higher-level events.
    10. The UI dApp’s registered listener (e.g., addNewTTListener) receives the event and updates its UI.
  • Cashing Out an Ingress Token:

    1. UI dApp determines the need to cash out (e.g., user click, autonomous logic).
    2. dApp retrieves the relevant CStateLessChannel (via manager.findChannelByID).
    3. dApp calls channel.cashOut(latestToken, myRecipientID).
    4. channel.cashOut formulates a #GridScript xTTEx command.
    5. Channel requests execution via CVMContext.processVMMetaDataKF.
    6. CVMContext sends the command to a Core Node.
    7. Core Node executes the GridScript, which involves DSM interaction (reading pool, verifying TT, updating pool state, updating balance). This occurs within an on-chain transaction context.
    8. Confirmation/Result might eventually propagate back via blockchain events or receipt listeners.
  • Token Pool Creation (via Mobile App):

    1. User/dApp initiates pool creation (e.g., in Wallet UI).
    2. UI dApp triggers a genPool request via CVMContext.processVMMetaDataKF (containing sacrificial receipt ID, dimensions, etc.).
    3. Core Node receives request, generates a specific QR Intent.
    4. CVMContext receives the QR Intent data via event and displays it (using UI dApp helpers).
    5. User scans QR with Mobile App.
    6. Mobile App securely generates the pool using MasterSeedHash, performs necessary signing.
    7. Mobile App sends the disarmed pool data + authorization back to the originating Core Node (via secure onion routing).
    8. Core Node receives the pool data.
    9. Core Node sends the pool data back to CVMContext via VM Meta-Data.
    10. CVMContext dispatches -> Manager.newVMMetaDataCallback receives pool data.
    11. Manager potentially creates a new CStateLessChannel instance.
    12. Manager raises onNewTokenPool/onNewChannel events -> CVMContext dispatches -> UI dApp is notified.
    13. (Separately) User/dApp initiates the CT (Commit Transaction) via QR to get the pool registered on-chain via DFS.

4. The CStateLessChannelsManager API (JavaScript)

The CStateLessChannelsManager is the primary interface for UI dApps to interact with the State-Less Channels system. It orchestrates the discovery, synchronization, and management of off-chain channels and related data. As a singleton service within the CVMContext, it ensures a consistent view and handling of channel operations across all UI dApps in a user session.

4.1. Accessing the Manager

Being a singleton managed by the CVMContext, you access the CStateLessChannelsManager instance as follows:

// Get the CVMContext instance (singleton)
const vmContext = CVMContext.getInstance();

// Get the State-Less Channels Manager instance
const channelsManager = vmContext.getChannelsManager;

// Now you can call methods on channelsManager
// e.g., channelsManager.findChannelByID(...)

4.2. Initialization and Lifecycle

The manager’s core functionality, including its autonomous operations, relies on an internal controller thread and event listeners connected to the CVMContext.

  • initialize():

    • Purpose:

      Starts the manager’s internal controller thread (a JavaScript timer loop) responsible for periodic tasks like channel synchronization and checking auto-cash-out conditions. It also registers the necessary internal listeners (newVMMetaDataCallback, newDFSMsgCallback) with the CVMContext.

    • Usage:

      This method is typically called automatically during the CVMContext‘s own initialization sequence. UI dApp developers usually do not need to call this directly.

    • Returns:

      void.

  • destroy():

    • Purpose:

      Stops the internal controller thread, preventing further autonomous operations. It does not automatically unregister event listeners registered by dApps.

    • Usage:

      Called when the CVMContext is shutting down or if explicitly needed to halt the manager’s background activity. UI dApp developers rarely need to call this.

    • Returns:

      void.

4.3. Channel Discovery and Management

These methods allow dApps to query the manager’s cache of known State-Less Channels.

  • findChannelByID(channelID, allowFriendlyID = true):

    • Purpose:

      Searches the manager’s internal list (mChannels) for a CStateLessChannel object matching the provided ID.

    • Parameters:

      • channelID (ArrayBuffer | String): The unique Token Pool ID (usually Base58Check encoded string) or a Friendly ID.
      • allowFriendlyID (Boolean): If true, the search will also match against the channel’s Friendly ID.
    • Returns:

      The CStateLessChannel object if found, otherwise null.

    • Example:

      const poolId = "2NPe49vveUrhF8WE5trVSTKRzcKPSFVdJqaFRBMKPUk"; // Example ID
      const channel = channelsManager.findChannelByID(poolId);
      if (channel && channel.getIsReadyForVerification) {
         console.log("Channel found and ready:", channel.getFriendlyID);
      } else if (channel) {
         console.log("Channel found but needs sync:", channel.getFriendlyID);
         // channel.synchronize(); // Optionally trigger sync
      } else {
         console.log("Channel not found locally.");
         // Might need to trigger discovery via syncAgentChannels if owner is known
      }
      
  • findChannelsByOwner(ownerID, allowFriendlyID = true):

    • Purpose:

      Finds all channels in the manager’s cache whose underlying Token Pool is owned by the specified ownerID.

    • Parameters:

      • ownerID (ArrayBuffer | String): The State Domain ID (or potentially Friendly ID if allowFriendlyID is true, though primarily designed for domain IDs) of the owner.
      • allowFriendlyID (Boolean): Allows matching ownerID against friendly IDs of the owner (less common use case).
    • Returns:

      An Array of CStateLessChannel objects owned by the specified ID, or an empty array if none are found.

  • getChannelIDs(mode = eChannelDirection.both, allowFriendlyIDs = true):

    • Purpose:

      Retrieves a list of IDs for all channels currently managed by the instance, filterable by direction (relative to the local user).

    • Parameters:

      • mode (eChannelDirection enum: ingress, outgress, both): Filters the channels based on their direction. ingress means the local user receives from the channel, outgress means the local user sends from the channel (owns the pool).
      • allowFriendlyIDs (Boolean): If true and a channel has a Friendly ID, that ID is returned instead of the raw Token Pool ID.
    • Returns:

      An Array of strings (Channel IDs or Friendly IDs).

4.4. Synchronization

These methods are used to update the local cache of channel states with the latest information from the DSM/DFS.

  • syncAgentChannels(agentID):

    • Purpose:

      Initiates a discovery and synchronization process for all State-Less Channels associated with a specific agentID (typically a State Domain ID). It does this by triggering a DFS doCD (Change Directory and List) command for the standard Token Pool directory (/agentID/TokenPools/) on a GRIDNET Core node. The results (list of .pool files) arrive asynchronously via the newDFSMsgCallback. The manager then typically queues doGetFile requests for each pool found.

    • Parameters:

      • agentID (ArrayBuffer | String): The State Domain ID of the agent whose channels should be synced.
    • Returns:

      Boolean indicating if the initial DFS request was successfully sent (does not guarantee channels were found or synced).

  • syncChannels(forceIt = false):

    • Purpose:

      Iterates through all currently managed channels (mChannels) and calls the synchronize() method on each one if forceIt is true or if the time since its last sync exceeds mChannelSyncInterval.

    • Parameters:

      • forceIt (Boolean): If true, forces synchronization regardless of the last sync time.
    • Returns:

      void.

  • mChannelSyncInterval (Property):

    • Purpose:

      A configuration value (in seconds, default 600) determining how often the manager’s controller thread attempts to automatically synchronize managed channels.

4.5. Autonomous Operations

The manager performs background tasks based on configured parameters.

  • Cash-out Logic:

    The internal controller thread (controllerThreadF) periodically calls cashOutChannels().

  • cashOutChannels(forceIt = false, autoCommit = true, channelIDsp = [], abortOnNotReady = true):

    • Purpose:

      (Primarily internal, but potentially callable) Checks managed ingress channels against configured thresholds (mCashOutChannelsAtValue, mCashOutChannelAfterTimout) or forces cash-out if forceIt is true. For qualifying channels, it formulates and queues xTTEx #GridScript commands via CVMContext to cash out the latest known mRecentToken.

    • Parameters:

      (See method signature for details, usually called internally without parameters).

    • Returns:

      Boolean indicating if any cash-out operations were initiated.

  • mCashOutChannelsAtValue (Property):

    Configurable threshold (GBU/Atto value) for auto cash-out.

  • mCashOutChannelAfterTimout (Property):

    Configurable time threshold (seconds) for auto cash-out.

4.6. Event Subscription API

UI dApps subscribe to these events to react to changes in the State-Less Channel ecosystem. All listener callbacks should ideally be async functions.

  • addNewTTListener(eventListener, appID = 0):

    • Triggered:

      When the Manager successfully processes an incoming CTransmissionToken (either a standard payment/reward or a Bank Update).

    • Callback Argument:

      An object { token: CTransmissionToken, isBankUpdate: Boolean }.

    • Purpose:

      Allows dApps to react to received off-chain value or bank updates.

    • Example:

      async function handleNewTT(event) {
        console.log(`Received TT for pool ${gTools.encodeBase58Check(event.token.getTokenPoolID())}`);
        if (event.isBankUpdate) {
          console.log("It's a bank update, refreshing spendable balance.");
          // Potentially update UI related to sending capabilities
        } else {
          const channel = channelsManager.findChannelByID(event.token.getTokenPoolID());
          const accumulated = channel ? await channel.getAccumulatedValue() : 0n;
          console.log(`Value in this TT: ${event.token.getValue()}. Total accumulated off-chain: ${accumulated}`);
          // Update UI with received value
        }
      }
      channelsManager.addNewTTListener(handleNewTT.bind(this), this.mID);
      
  • addNewTokenPoolListener(eventListener, appID = 0):

    • Triggered:

      When the Manager discovers or receives data for a CTokenPool object for the first time in the current session (often as a result of syncAgentChannels or direct VM Meta-Data). Note: addNewStateChannelListener is usually triggered subsequently or concurrently.

    • Callback Argument:

      An object { pool: CTokenPool, requestID: Number }.

    • Purpose:

      Informs dApps about the existence and initial state of a Token Pool.

  • addNewStateChannelListener(eventListener, appID = 0):

    • Triggered:

      When the Manager creates a new CStateLessChannel object instance to manage a discovered Token Pool. This signifies the channel is now being actively tracked.

    • Callback Argument:

      An object { channel: CStateLessChannel, requestID: Number }.

    • Purpose:

      Allows dApps to know when a new channel becomes managed and potentially start interacting with it or updating UI lists.

  • addNewTransitPoolListener(eventListener, appID = 0):

    • Clarification Needed:

      The concept of a “Transit Pool” event is less distinct in the current State-Less model compared to the underlying CTransmissionToken and CTokenPool updates. This listener’s specific trigger condition might overlap significantly with TT or Receipt events.

      It’s likely related to the completion or receipt of an on-chain cash-out (xTTEx) transaction.

      Developers should currently rely more on addNewTTListener for off-chain updates and addNewReceiptListener for on-chain settlement confirmation. Further clarification from core implementation might be needed.

  • addNewReceiptListener(eventListener, appID = 0):

    • Triggered:

      When a transaction receipt arrives via CVMContext that corresponds to a previously initiated State-Less Channel operation (e.g., a cash-out xTTEx transaction or pool registration). The manager needs internal logic to correlate receipts to channel operations.

    • Callback Argument:

      An object { receipt: CReceipt } (Structure of CReceipt needs definition – likely contains TX ID, status, block info).

    • Purpose:

      Allows dApps to confirm that an on-chain action related to a channel (like cashing out) has been successfully finalized on the DSM.

  • addStateChannelNewStateListener(eventListener, appID = 0):

    • Triggered:

      When the Manager processes an event (like a new TT or a successful pool sync) that results in a change to the cached state of a managed CStateLessChannel (e.g., its mTokenPool‘s bank depths are updated).

    • Callback Argument:

      An object { channel: CStateLessChannel, newState: Object, previousState: Object | null }. The state objects contain key metrics like availableAssets, spendableAssets, accumulatedAssets.

    • Purpose:

      Enables dApps to reactively update UI elements displaying channel balances or status based on processed off-chain or synchronized on-chain data.

4.7. Internal Callbacks (Manager’s Perspective)

These are the methods the Manager uses to listen to the CVMContext. UI dApp developers typically don’t interact with these directly but understanding them helps clarify the flow.

  • newVMMetaDataCallback(metaMsg):

    • Handles incoming VM Meta-Data messages.
    • Parses the data using CVMMetaParser.
    • Looks specifically for eVMMetaSectionType.stateLessChannels sections.
    • Deserializes elements like CTransmissionToken or CTokenPool based on eVMMetaEntryType.StateLessChannelsElement and eStateLessChannelsElementType.
    • Calls internal onTT or onTokenPoolReceived methods.
  • newDFSMsgCallback(dfsMsg):

    • Handles responses to DFS requests initiated by the Manager or Channels (e.g., doCD, doGetFile).
    • Parses the DFS message and potential embedded VM Meta-Data (dfsMsg.getData1).
    • If it’s a directory listing (doCD response), it might trigger doGetFile requests for found .pool files.
    • If it’s file content (doGetFile response for a .pool file), it deserializes the CTokenPool.
    • Calls internal onTokenPoolReceived.
  • Internal Event Raisers (onTT, onNewTokenPool, etc.):

    • These private/internal methods within the Manager are called by the callbacks above after successfully processing data.
    • They perform core logic (e.g., finding/updating the relevant channel object).
    • They are responsible for finally raising the public events (e.g., addNewTTListener, addNewStateChannelListener) that UI dApps subscribe to.

5. The CStateLessChannel API (JavaScript – Key Aspects)

While the CStateLessChannelsManager provides overall coordination, the CStateLessChannel class represents a single, specific channel instance. UI dApps typically obtain instances of this class from the manager (e.g., via findChannelByID) rather than constructing them directly. This section highlights the most important methods and properties developers will interact with.

5.1. Object Lifecycle and State

These methods and properties relate to the creation, readiness, and basic information of a channel instance.

  • constructor(tokenPoolID = null):

    • Purpose:

      Creates a new CStateLessChannel object instance associated with a specific Token Pool ID.

    • Parameters:

      • tokenPoolID (ArrayBuffer | String): The unique ID of the Multi-Dimensional Token Pool this channel represents.
    • Note:

      While constructible, instances are typically managed and provided by the CStateLessChannelsManager. Direct instantiation by a dApp is uncommon.

  • synchronize():

    • Purpose:

      Initiates a request (via the Manager and CVMContext) to fetch the latest state data for the associated Token Pool from the DSM/DFS. This updates the channel’s internal cached mTokenPool object.

    • Parameters:

      None.

    • Returns:

      Boolean indicating if the synchronization request was successfully sent. The actual data arrives asynchronously via events.

    • Usage:

      Call this when you need the most up-to-date on-chain state for a channel, especially before critical operations like validating a newly received high-value token or attempting a cash-out, or if the channel’s getIsReadyForVerification is false. Be mindful of rate limits.

  • getIsReadyForVerification (Getter):

    • Purpose:

      Checks if the channel instance has successfully loaded its corresponding CTokenPool data from the DSM/DFS (i.e., mTokenPool is not null).

    • Parameters:

      None.

    • Returns:

      Boolean. true if the pool data is loaded and TT validation can be attempted, false otherwise.

  • getID() (Getter):

    • Purpose:

      Returns the unique Token Pool ID (as an ArrayBuffer) associated with this channel.

  • getFriendlyID() (Getter):

    • Purpose:

      Returns the human-readable friendly identifier assigned to the Token Pool, if one exists.

    • Returns:

      String, potentially empty if no friendly ID is set.

  • getTokenPool() (Getter):

    • Purpose:

      Returns the internally cached CTokenPool object instance containing the detailed state (banks, depths, etc.) for this channel.

    • Returns:

      CTokenPool object or null if not yet synchronized.

  • getIsOutgress (Getter):

    • Purpose:

      Determines if this channel represents an outbound payment stream from the perspective of the currently logged-in user. This means the logged-in user owns the underlying Token Pool. It compares the pool’s owner ID with the user’s ID from CVMContext.

    • Returns:

      Boolean. true if the local user owns the pool (Outgress), false if someone else owns it (Ingress), or potentially false or throws an error if the user isn’t logged in or pool data is unavailable.

  • Timestamps (getLastTimeUsed(), getLastTimeUpdated(), getLastTimeCashedOut(), getTimeSince...() methods):

    • Purpose:

      Provide access to timestamps (Unix epoch seconds) tracking key events in the channel’s lifecycle within the current session. getTimeSince...() methods return the duration in seconds since that event.

    • Note:

      These are primarily informative for the local session and may reset when the session restarts. The core on-chain state is managed by the DSM.

  • ping(type = eChannelLocalPingType.lastUpdate):

    • Purpose:

      (Mostly internal) Updates the internal timestamp specified by the type enum (update, lastUsed, lastSync, lastCashOut).

5.2. Generating Transmission Tokens

These methods are used by UI dApps managing

Outgress

channels (where the local user owns the pool) to create TTs for sending off-chain payments.

  • getTTForPeer(value, peerID = '', markUsed = true, reassignDimensionsIfNeeded = true):

    • Purpose:

      High-level method to generate a CTransmissionToken for a specific value destined for a specific peer. It handles the logic of finding an appropriate, available bank (dimension) within the pool, potentially assigning a free bank to the peer if none is currently assigned or if the previously assigned one is depleted/insufficient.

    • Parameters:

      • value (BigInt | Number): The GBU/Atto value the token should represent.
      • peerID (ArrayBuffer | String): The ID of the intended recipient. This helps the channel manage bank assignments. If empty, it attempts to find the first available unassigned bank with sufficient value.
      • markUsed (Boolean): If true (default), updates the internal state of the chosen bank as if the token was spent locally (decrements available value, increments usage depth). Set to false only for inspection/simulation.
      • reassignDimensionsIfNeeded (Boolean): If true (default), allows the method to automatically assign a new free bank to the peer if their currently assigned bank is unsuitable (e.g., depleted).
    • Returns:

      A CTransmissionToken object on success, null if no suitable bank/dimension could be found or assigned, or if the pool lacks sufficient total spendable value.

  • getTTWorthValue(value, bankID = -1, markUsed = true):

    • Purpose:

      Lower-level method to generate a CTransmissionToken for a specific value from a specific bank, or the first available unassigned bank if bankID is -1. It does not perform automatic peer-to-bank assignment management like getTTForPeer.

    • Parameters:

      • value (BigInt | Number): The GBU/Atto value.
      • bankID (Number): The index of the specific dimension/bank to use. If -1, it searches for the first unassigned bank with enough value.
      • markUsed (Boolean): Updates the internal bank state if true.
    • Returns:

      A CTransmissionToken object on success, null if the specified (or first found) bank lacks sufficient value or is invalid.

5.3. Validating Transmission Tokens

These methods are primarily used by UI dApps managing

Ingress

channels to verify incoming TTs and check available balances.

  • validateTT(token, updateState = true, isBankUpdate = false):

    • Purpose:

      The core method to validate an incoming CTransmissionToken against the channel’s cached CTokenPool state. It performs the necessary cryptographic hash chain verification and checks if the token represents a valid progression from the currently known usage depth of the bank.

    • Parameters:

      • token (CTransmissionToken): The token object to validate.
      • updateState (Boolean): If true (default) and the token is valid, updates the internal cached state of the CTokenPool (specifically, the bank’s mCurrentDepth and mCurrentFinalHash). This should generally be true when processing received payments.
      • isBankUpdate (Boolean): If true, indicates this token is a special update from the pool owner (via mobile app) meant to reveal more spendable assets from an outgress channel, rather than representing a payment received. It updates the bank’s pre-cached seed hash instead of its usage depth.
    • Returns:

      BigInt representing the value of the newly validated token segment (i.e., token.getRevealedHashesCount() * tokenPool.getSingleTokenValue()) if valid, 0n if invalid (e.g., double-spend attempt, hash mismatch), or -1n if the channel is not ready (mTokenPool is null).

  • getAccumulatedValue() (Getter):

    • Purpose:

      Calculates the total value represented by the last known valid CTransmissionToken (mRecentToken) received for this channel in the current session, relative to the pool’s initial state (or last cash-out state if known locally). Essentially, it checks how much value the mRecentToken represents if it were to be cashed out now.

    • Returns:

      BigInt representing the potential cash-out value based on the last token, 0n if no token has been received or validated, or the pool data isn’t ready.

  • getLocallySpendableAssets() (Getter):

    • Purpose:

      Relevant primarily for

      Outgress

      channels. Calculates the amount of value the local user can currently spend off-chain without needing further interaction with their mobile app. This relies on the depth of pre-cached seed hashes potentially provided by the mobile app as “Bank Updates”.

    • Returns:

      BigInt representing the spendable value based on pre-cached data, 0n if no pre-cached hashes are available beyond the current on-chain usage depth.

5.4. Cashing Out

This method initiates the process of settling the off-chain value onto the main blockchain.

  • cashOut(token, awardeeID, autoCommit = false):

    • Purpose:

      Creates and sends the #GridScript xTTEx command (via the Manager and CVMContext) to a Core Node to initiate the on-chain cash-out process for the value represented by the provided token.

    • Parameters:

      • token (CTransmissionToken): The latest valid token received for the channel/bank that is to be cashed out. This token implicitly covers all value since the last on-chain settlement for that bank.
      • awardeeID (ArrayBuffer | String): The State Domain ID of the entity who should receive the funds on-chain (usually the local user for an Ingress channel).
      • autoCommit (Boolean): If true, attempts to immediately trigger a full commit procedure via CVMContext.commit() after queueing the xTTEx command (less common, usually commit is handled separately).
    • Returns:

      Boolean indicating if the xTTEx command was successfully sent to the CVMContext for processing. It does not guarantee the cash-out succeeded on-chain. Confirmation comes via events (addNewReceiptListener).

5.5. Bank (Dimension) Management

These methods provide finer control over how peers are associated with specific dimensions, primarily useful for Outgress channels in complex reward scenarios.

  • assignPeerToBank(peerID, bankID):

    Explicitly associates a peer with a bank ID in the channel’s internal map (mRecipientsToBanks).

  • isBankInUse(bankID):

    Checks if a specific bank ID is currently assigned to any peer in the internal map.

  • findBankForUser(peerID):

    Looks up the CTokenPoolBank object currently assigned to the given peer ID.

  • freeBank(bankID):

    Removes any association for the given bank ID from the internal map, making it available for assignment to another peer.

I’ll convert the content into HTML with the same formatting style as your existing HTML fragment. Here’s the converted HTML:

5.6. Token Pool Synchronization

5.6.1. When Token Pool Updates Are Needed

Token Pools stored in the web browser’s environment need to be synchronized with their authoritative state on the DSM/DFS under several circumstances:

  • Initial Discovery: When a UI dApp first encounters a Token Pool ID, it needs to retrieve the pool’s data to create a local CTokenPool instance.
  • Periodic Refresh: The pool’s on-chain state may change due to other participants’ actions (cash-outs) occurring in parallel sessions.
  • Before Critical Operations: Prior to sending or validating high-value Transmission Tokens, or before cashing out.
  • After Suspected Staleness: If a TT validation or generation fails unexpectedly, the local pool cache might be out of date.
  • After Cash-Out Operations: After a successful cash-out transaction, the pool’s bank usage depths have changed on-chain.

5.6.2. Synchronization Mechanism

The synchronization process involves the following steps:

// Within a UI dApp
async function updatePoolState(channelId) {
  const manager = this.mVMContext.getChannelsManager;
  const channel = manager.findChannelByID(channelId);
  
  if (channel) {
    // Trigger synchronization with on-chain state
    const syncSuccess = await channel.synchronize();
    
    if (syncSuccess) {
      console.log("Channel synchronized successfully");
      // Update UI with fresh data
      this.updateChannelDisplay(channelId);
    } else {
      console.warn("Channel synchronization failed");
    }
  }
}

Under the hood, synchronize() calls getPoolEx via CVMContext to fetch the latest Token Pool data from the DFS. This updates the bank usage depths and other state information to match the on-chain reality.

5.6.3. Automatic vs. Manual Synchronization

The CStateLessChannelsManager provides both automatic and manual synchronization options:

  • Automatic Synchronization

    • The manager’s internal controller thread (controllerThreadF) periodically calls syncChannels() at intervals defined by mChannelSyncInterval (default: 600 seconds).
    • This ensures all managed channels are kept reasonably up-to-date without developer intervention.
  • Manual Synchronization

    • Developers should manually trigger synchronization in these cases:
  • Before Sending Value: Before generating a new TT to ensure the channel has sufficient spendable value:
    // Check readiness before sending
    if (!channel.getIsReadyForVerification()) {
      await channel.synchronize();
    }
    const tt = await channel.getTTWorthValue(valueAtto, recipientId);
  • Before Cashing Out: To ensure the most recent state is considered:
    await channel.synchronize();
    const accumulatedValue = await channel.getAccumulatedValue();
    if (accumulatedValue > 0n) {
      channel.cashOut(latestToken, myDomainID);
    }
  • After Failed Operations: If TT validation or generation fails unexpectedly:
    if (await channel.validateTT(token) === 0n) {
      // Token appears invalid, synchronize and try again
      await channel.synchronize();
      const validationResult = await channel.validateTT(token);
      // Handle result...
    }

5.6.4. Checking Synchronization Status

Before performing critical operations, UI dApps should check if a channel is ready for verification:

const channel = manager.findChannelByID(channelId);
if (channel) {
  if (channel.getIsReadyForVerification()) {
    // Channel's local cache is valid and ready for use
    proceedWithOperation();
  } else {
    // Channel needs synchronization
    await channel.synchronize();
    if (channel.getIsReadyForVerification()) {
      proceedWithOperation();
    } else {
      // Still not ready, handle error case
      showError("Channel data could not be synchronized");
    }
  }
}

5.6.5. Synchronization and Events

When synchronization completes, the CStateLessChannelsManager raises appropriate events:

  • If significant state changes occurred, onChannelNewState will be triggered

UI dApps can react to these events to update their display:

// Register for state changes
manager.addStateChannelNewStateListener(this.handleChannelStateChange.bind(this), this.mID);

// Handle state changes, including those from synchronization
async handleChannelStateChange(event) {
  const channel = event.channel;
  const newState = event.newState;
  
  // Update UI with new state information
  this.updateBalanceDisplay(channel.getID(), newState.availableAssets);
  this.updateSpendableDisplay(channel.getID(), newState.spendableAssets);
}

5.6.6. Best Practices

  • Responsive Synchronization: Trigger synchronization in response to user actions that will use channel data
  • Avoid Over-Synchronization: Don’t synchronize on every UI update; rely on the automatic process and only manually sync before critical operations
  • Graceful Degradation: Handle failed synchronization attempts gracefully, possibly by retrying once and then displaying appropriate error messages
  • UI Feedback: Show synchronization status to users during critical operations to set expectations around timing
  • Cached Data Awareness: Clearly distinguish in the UI between data known to be current and potentially stale data

By applying these synchronization strategies, UI dApps can ensure they operate with the most up-to-date Token Pool state while minimizing unnecessary network traffic and providing a responsive user experience.


6. Under the Hood: GridScript and VM Meta-Data Protocol

While UI dApp developers primarily interact with the high-level CStateLessChannelsManager and CStateLessChannel JavaScript APIs, these APIs act as wrappers around lower-level system interactions involving #GridScript commands, the VM Meta-Data exchange protocol, and the Decentralized File System (DFS). Understanding this underlying flow provides deeper insight into the system’s operation.

6.1. Mapping JS API to GridScript

Many key operations initiated through the JavaScript API translate directly into specific #GridScript commands executed by GRIDNET Core nodes on the DSM. The CVMContext and CStateLessChannelsManager handle the formulation and dispatch of these commands.

  • CStateLessChannel.cashOut(token, awardeeID) -> xTTEx command:

    • When a dApp calls cashOut(), the CStateLessChannel object (often via the Manager) prepares the necessary parameters (the BER-encoded CTransmissionToken data and the awardeeID).
    • These parameters are pushed onto the #GridScript stack.
    • The xTTEx command is invoked within a transaction context (BT/CT).
    • The Core node executes xTTEx, which performs the on-chain validation, updates the Token Pool state on DFS, and adjusts the awardee’s balance on the DSM.
    • User-friendly wrapper: The xtt command in the Terminal Interface acts as an inline parameter wrapper for xTTEx.
  • CStateLessChannel.synchronize() -> getPoolEx command (via getPool wrapper):

    • Calling synchronize() triggers a request to fetch the latest Token Pool data.
    • Internally, this results in the getPoolEx #GridScript command being executed on a Core node. The Token Pool ID is pushed onto the stack first.
    • getPoolEx reads the corresponding .pool file from DFS.
    • The result (the BER-encoded pool data or an error/null indicator) is packaged into a VM Meta-Data message and sent back to the originating CVMContext.
    • User-friendly wrapper: The getPool command in the Terminal Interface acts as an inline parameter wrapper for getPoolEx.
  • Mobile App QR Intent for Pool Creation -> genPoolEx command:

    • The process initiated by a UI dApp to create a pool results in a QR Intent containing specific VM Meta-Data for the Mobile App.
    • The Mobile App securely generates the (disarmed) Token Pool data.
    • This data is returned to the Core Node serving the user’s session.
    • To register this pool on-chain, a transaction containing the genPoolEx command is ultimately created. The necessary parameters (owner ID, receipt ID, pool parameters, disarmed pool data) are pushed onto the stack before genPoolEx is called.
    • genPoolEx validates the parameters and writes the pool data to the appropriate DFS location.
    • User-friendly wrapper: The genpool command handles parsing inline parameters and invoking genPoolEx.
  • Parameter Passing Mechanisms:

    • Stack-based:

      Core #GridScript functions (often suffixed with Ex) typically expect parameters to be pushed onto the data stack in a specific order before they are invoked, similar to traditional Forth. The JavaScript APIs handle this internally.

    • Inline Parameters:

      For user convenience in the Terminal Interface, many commands have wrappers (like xtt, getPool, genpool) that accept parameters directly on the command line (e.g., xtt -t <token> -r <rewardee>). These wrappers parse the inline arguments and push them correctly onto the stack before calling their Ex counterparts.

6.2. VM Meta-Data (eVMMetaSectionType.stateLessChannels)

The VM Meta-Data protocol is the primary channel for structured communication between the CVMContext (representing the UI environment) and the Core Nodes. State-Less Channels have a dedicated section type.

  • Structure of eVMMetaEntryType.StateLessChannelsElement:

    When a Core Node needs to send channel-related data to the UI (e.g., an incoming TT, a response to getPoolEx), it packages it within a VM Meta-Data message using:

    • Section Type:

      eVMMetaSectionType.stateLessChannels

    • Entry Type:

      eVMMetaEntryType.StateLessChannelsElement

    • Entry Data Fields:

      Typically contains:

      1. elementType (eStateLessChannelsElementType enum): Specifies the type of payload.
      2. name (ArrayBuffer/String): Often the Token Pool ID or a related identifier.
      3. data (ArrayBuffer): The BER-encoded payload (e.g., the CTransmissionToken or CTokenPool data).
  • Element Types (eStateLessChannelsElementType):

    The elementType field distinguishes the payload:

    • token: Contains BER-encoded CTransmissionToken data representing a payment/reward.
    • tokenPool: Contains BER-encoded CTokenPool data (usually a response to getPoolEx).
    • transitPool: Conceptual. While defined, direct transmission of an aggregated “Transit Pool” structure is less common; cash-out typically uses the latest token. Events related to successful cash-out might use this type or receipt.
    • receipt: Contains information about a finalized on-chain transaction related to a channel operation (e.g., a cash-out receipt).
    • bankUpdate: Contains BER-encoded CTransmissionToken data specifically flagged as a bank update from the owner (via Mobile App), used to reveal more spendable assets for an Outgress channel.
  • How CVMContext Routes Data:

    1. CVMContext receives a VM Meta-Data message from a Core Node.
    2. It parses the message and identifies sections/entries.
    3. If it finds a section of type stateLessChannels, it iterates through its StateLessChannelsElement entries.
    4. It dispatches a generic newVMMetaData event containing the raw metaMsg.
    5. The CStateLessChannelsManager, subscribed to this event via newVMMetaDataCallback, receives the metaMsg.
    6. The Manager specifically looks for the stateLessChannels section, extracts the elementType and BER-encoded data from relevant entries.
    7. It deserializes the data into the appropriate JavaScript object (CTokenPool, CTransmissionToken).
    8. It then processes this object internally (e.g., finds the target CStateLessChannel) and raises the specific, higher-level API events (e.g., onTT, onNewTokenPool) for subscribed UI dApps.

6.3. Decentralized File System (DFS) Interaction

The DFS provides persistent, replicated storage essential for the State-Less Channels system.

  • Storing Token Pools:

    The public data of a Multi-Dimensional Token Pool, once generated and committed via genPoolEx, is stored as a regular file within the owner’s State Domain on the DFS. Conventionally, these files have a .pool extension and reside in a TokenPools subdirectory (e.g., /OwnerID/TokenPools/PoolID.pool).

  • Discovery (doCD):

    The CStateLessChannelsManager uses the doCD DFS command (sent via CVMContext) to list the contents of an owner’s /TokenPools/ directory. This is how it discovers the IDs (filenames) of pools belonging to a specific agent during the syncAgentChannels process.

  • Retrieval (doGetFile):

    Once a pool’s filename (ID) is known (either from discovery or because the dApp already knew it), the Manager or CStateLessChannel triggers a doGetFile DFS command (via CVMContext) to retrieve the file’s content.

  • How CVMContext Routes DFS Data:

    1. CVMContext receives a DFS message response (e.g., directory listing from doCD, file content from doGetFile) from a Core Node.
    2. It dispatches a generic newDFSMsg event containing the dfsMsg object. Note that DFS file content responses often embed the content within a VM Meta-Data structure inside the DFS message’s Data1 field.
    3. The CStateLessChannelsManager, subscribed via newDFSMsgCallback, receives the dfsMsg.
    4. It checks if the request ID matches one it initiated (hasDFSRequestID).
    5. It parses the message type. If it’s a directory listing, it might queue doGetFile requests. If it’s file content (eDFSElementType.fileContent), it parses the embedded VM Meta-Data, extracts the BER-encoded CTokenPool data from the appropriate field.
    6. It deserializes the pool data.
    7. It calls its internal onTokenPoolReceived method, which finds/updates the relevant CStateLessChannel and raises events for UI dApps.

7. Practical Usage & Examples (UI dApp Perspective)

This section provides practical code examples and outlines common scenarios for UI dApps interacting with the GRIDNET OS State-Less Channels system via the CVMContext and CStateLessChannelsManager. These examples assume they are running within the context of a class extending CWindow, where this.mVMContext refers to the CVMContext singleton and this.mID is the dApp’s process ID.

7.1. Setup: Getting the Manager, Subscribing to Events

Before interacting with channels, your dApp needs access to the manager and should subscribe to relevant events within its initialization logic (e.g., in the constructor or an initialize method).

class MyDApp extends CWindow {
    constructor( /* ... CWindow params */ ) {
        super( /* ... CWindow params */ );
        this.mVMContext = CVMContext.getInstance();
        this.mChannelsManager = this.mVMContext.getChannelsManager;
        this.myChannelListeners = []; // Keep track of listener IDs for cleanup

        this.initializeEventListeners();
    }

    initializeEventListeners() {
        // Subscribe to new incoming Transmission Tokens
        let listenerIdTT = this.mChannelsManager.addNewTTListener(this.handleNewTT.bind(this), this.mID);
        this.myChannelListeners.push(listenerIdTT);

        // Subscribe to channel state changes (e.g., balance updates after sync/TT validation)
        let listenerIdState = this.mChannelsManager.addStateChannelNewStateListener(this.handleChannelStateChange.bind(this), this.mID);
        this.myChannelListeners.push(listenerIdState);

        // Subscribe to cash-out confirmations (optional but recommended)
        let listenerIdReceipt = this.mChannelsManager.addNewReceiptListener(this.handleReceipt.bind(this), this.mID);
        this.myChannelListeners.push(listenerIdReceipt);

        // Subscribe to newly managed channels (optional, e.g., for dynamic list updates)
        let listenerIdNewChannel = this.mChannelsManager.addNewStateChannelListener(this.handleNewChannel.bind(this), this.mID);
        this.myChannelListeners.push(listenerIdNewChannel);
    }

    // --- Callback Handlers (defined later) ---
    async handleNewTT(event) { /* ... */ }
    async handleChannelStateChange(event) { /* ... */ }
    async handleReceipt(event) { /* ... */ }
    async handleNewChannel(event) { /* ... */ }


    closeWindow() {
        // IMPORTANT: Unregister listeners when the dApp closes to prevent memory leaks
        this.myChannelListeners.forEach(listenerId => {
            this.mVMContext.unregisterEventListenerByID(listenerId); // Use CVMContext to unregister
        });
        this.myChannelListeners = [];
        super.closeWindow(); // Call parent class method
    }

    // ... other dApp methods ...
}

7.2. Use Case 1: Receiving Real-time Micropayments (e.g., Game Rewards)

Your dApp needs to react when a new off-chain payment arrives.

// Inside MyDApp class

async handleNewTT(event) {
    const token = event.token;
    const isBankUpdate = event.isBankUpdate;
    const poolIdStr = gTools.encodeBase58Check(token.getTokenPoolID());

    console.log(`Received TT for pool: ${poolIdStr}, Is Bank Update: ${isBankUpdate}`);

    if (isBankUpdate) {
        // This is likely for an Outgress channel owned by the user,
        // updating the spendable balance. React accordingly if needed.
        console.log("Bank update received, potentially more funds available to send.");
        return;
    }

    // It's a potential payment/reward for an Ingress channel
    const channel = this.mChannelsManager.findChannelByID(token.getTokenPoolID());

    if (!channel) {
        console.warn(`Received TT for unknown channel ${poolIdStr}. Manager will attempt to sync.`);
        // The manager might automatically create the channel object later
        // after fetching pool data via DFS triggered by the unknown TT.
        return;
    }

    if (channel.getIsOutgress) {
        console.log(`Ignoring TT for Outgress channel ${poolIdStr} (likely sent by this user).`);
        return; // Usually not interested in tokens you generated yourself
    }

    // --- Validate without immediately updating the channel's core state ---
    // This tells you the value of *this specific token*, assuming it's valid
    // relative to the *currently cached* pool state.
    const newlyReceivedValue = await channel.validateTT(token, false); // false = don't update state yet

    if (newlyReceivedValue > 0n) {
        console.log(`Valid TT received representing ${newlyReceivedValue} Atto`);

        // --- Now update the channel state with this valid token ---
        // This marks the token as 'seen' locally for accumulation calculation
        await channel.validateTT(token, true); // true = update cached state
        channel.setRecentToken = token; // Store the latest valid token

        // --- Get the total potential cash-out value based on the *latest* token ---
        const accumulatedValue = await channel.getAccumulatedValue();
        console.log(`Total accumulated off-chain value for channel ${channel.getFriendlyID || poolIdStr}: ${accumulatedValue} Atto`);

        // --- Update your UI ---
        this.updateMyGameScoreDisplay(poolIdStr, accumulatedValue); // Example UI update function

    } else if (newlyReceivedValue === 0n) {
        console.warn(`Received TT for channel ${poolIdStr} is invalid or a replay.`);
        // E.g., Double spend attempt, or hash chain mismatch. Ignore it.
    } else { // -1n
        console.warn(`Cannot validate TT for channel ${poolIdStr} yet, pool data not ready.`);
        // Need to wait for channel.synchronize() to complete.
    }
}

updateMyGameScoreDisplay(channelId, accumulatedValue) {
    // Find the UI element representing this channel/score and update it
    // Example: document.getElementById(`score_${channelId}`).innerText = `${gTools.attoToGNCStr(accumulatedValue)} GNC`;
    console.log(`UI Update: Channel ${channelId} accumulated ${gTools.attoToGNCStr(accumulatedValue)} GNC`);
}

7.3. Use Case 2: Cashing Out Received Tokens

When the user wants to convert their accumulated off-chain rewards into on-chain balance.

// Inside MyDApp class

async cashOutChannel(channelId) {
    const channel = this.mChannelsManager.findChannelByID(channelId);

    if (!channel) {
        this.showError("Channel not found.");
        return;
    }

    if (channel.getIsOutgress) {
        this.showError("Cannot cash out from an Outgress channel.");
        return;
    }

    const latestToken = channel.getRecentToken;
    if (!latestToken) {
        this.showError("No valid tokens received to cash out for this channel yet.");
        return;
    }

    const accumulatedValue = await channel.getAccumulatedValue();
    if (accumulatedValue <= 0n) {
        this.showError("Accumulated value is zero, nothing to cash out.");
        return;
    }

    const myDomainID = this.mVMContext.getUserID(); // Or getUserFullID()
    if (!myDomainID || myDomainID.length === 0) {
        this.showError("Cannot cash out: User ID not available. Please log in.");
        // Trigger login flow if necessary
        // this.mVMContext.requestQRLogon();
        return;
    }

    console.log(`Attempting to cash out ${accumulatedValue} Atto from channel ${channel.getFriendlyID || channelId} to ${myDomainID}`);
    this.showLoadingIndicator(`Cashing out ${gTools.attoToGNCStr(accumulatedValue)} GNC...`);

    // Initiate the cash-out process
    const requestSent = channel.cashOut(latestToken, myDomainID, false); // false = don't auto-commit yet

    if (!requestSent) {
        this.hideLoadingIndicator();
        this.showError("Failed to send cash-out request to the network.");
    } else {
        console.log("Cash-out request queued. Waiting for confirmation via receipt listener or commit.");
        // The actual commit might happen later via the Magic Button or another dApp action.
        // The handleReceipt callback will be triggered upon confirmation.
    }
}

// Callback for transaction receipts
async handleReceipt(event) {
    const receipt = event.receipt;
    // TODO: Need logic to correlate this receipt specifically to our cash-out transaction.
    // This might involve checking TX type, involved parties, or matching against
    // a TX ID stored when cashOut() was called (if the API provided it).
    // For now, assume any relevant receipt means success/failure.
    console.log("Received a transaction receipt:", receipt);
    this.hideLoadingIndicator();
    if (receipt.status === 'success') { // Assuming receipt structure
        this.showMessage("Cash-out successful!");
        // Optionally, re-sync the channel state or balance after confirmation
        // this.mVMContext.retrieveBalance(true);
    } else {
        this.showError(`Cash-out failed: ${receipt.errorMessage || 'Unknown error'}`);
    }
}

7.4. Use Case 3: Creating a Token Pool (e.g., for a Game Server/Service)

Creating a pool requires an on-chain sacrificial transaction and secure generation using the MasterSeedHash, typically involving the mobile app.

// Inside MyDApp class (e.g., an admin panel dApp)

async createTokenPool(totalValueGNC, numDimensions, friendlyId = "") {
    const totalValueAtto = gTools.GNCToAtto(totalValueGNC); // Convert GNC to Atto

    // 1. Perform the Sacrificial Transaction (Requires separate logic/UI)
    // This would involve using CVMContext.processGridScript to send GNC
    // to a specific system address or using a dedicated 'sacrifice' command.
    // You need the receipt ID of this transaction.
    const sacrificialReceiptId = await this.performSacrifice(totalValueAtto); // Placeholder function
    if (!sacrificialReceiptId) {
        this.showError("Sacrificial transaction failed.");
        return;
    }
    console.log(`Sacrifice successful, Receipt ID: ${sacrificialReceiptId}`);

    // 2. Prepare the QR Intent for Mobile App Generation
    const ephKeyPair = this.mVMContext.getKeyPair;
    const myOwnerId = this.mVMContext.getUserFullID(); // Use full ID for ownership
    const valuePerToken = 1n; // Example: 1 Atto per token

    // Create a *template* CTokenPool object (most values are placeholders here)
    // The mobile app calculates depths and generates hashes based on parameters
    const poolTemplate = new CTokenPool(
        null, // CryptoFactory not needed here
        numDimensions,
        myOwnerId,
        sacrificialReceiptId, // Link to the sacrifice
        valuePerToken,
        totalValueAtto,
        0n, // CurrentIndex (starts at 0)
        friendlyId
        // Seed/Final/Current hashes are generated by mobile app
    );

    const metaGen = new CVMMetaGenerator();
    // The addGenTokenPoolRequest prepares the specific VM Meta-Data structure
    // that tells the mobile app what parameters to use for generation.
    metaGen.addGenTokenPoolRequest(poolTemplate);

    const qr = new CQRIntent(
        eQRIntentType.QRProcessVMMetaData, // Instructs mobile app to process the metadata
        this.mVMContext.getConversationID(), // Target this web session
        this.mVMContext.getFullNodeIP(), // Route through this node
        eEndpointType.WebSockConversation
    );
    qr.setPubKey(ephKeyPair.public);
    qr.setData(metaGen.getPackedData()); // Embed the generation request

    // Display the QR code to the user
    this.showQRCode(qr); // Placeholder UI function to display the QR object
    console.log("Please scan the QR code with your GRIDNET Token app to generate the Token Pool securely.");

    // 3. Wait for the Response
    // The mobile app will generate the pool, send the disarmed data back to the Core node,
    // which sends it via VM Meta-Data to CVMContext -> ChannelsManager.
    // Your dApp will be notified via the addNewTokenPoolListener / addNewStateChannelListener.
    // The dApp then needs to initiate the *second* transaction (BT... genPoolEx ... CT)
    // using the received disarmed pool data to register it on-chain.
}

7.5. Use Case 4: Sending Off-Chain Rewards/Payments (Outgress Channel)

Using a pool you own to send value to another peer off-chain.

// Inside MyDApp class

async sendOffChainPayment(poolId, recipientId, valueAtto) {
    const channel = this.mChannelsManager.findChannelByID(poolId);

    if (!channel) {
        this.showError(`Channel ${poolId} not found or managed.`);
        return;
    }

    if (!channel.getIsOutgress) {
        this.showError(`Channel ${poolId} is not an Outgress channel you own.`);
        return;
    }

    if (!channel.getIsReadyForVerification) {
        this.showError(`Channel ${poolId} is not synchronized. Please sync first.`);
        // await channel.synchronize(); // Optionally trigger sync
        return;
    }

    console.log(`Attempting to generate TT for ${valueAtto} Atto to ${recipientId} from pool ${poolId}`);

    // Use getTTForPeer for automatic bank management
    const transmissionToken = await channel.getTTForPeer(valueAtto, recipientId, true); // true = mark as used locally

    if (!transmissionToken) {
        const spendable = await channel.getLocallySpendableAssets();
        this.showError(`Failed to generate TT. Insufficient funds in available banks or no free banks. Locally Spendable: ${spendable} Atto`);
        // May need a bank update from mobile app if spendable is low but total valueLeft is high
        return;
    }

    console.log("Transmission Token generated successfully:", transmissionToken);

    // --- Deliver the Transmission Token ---
    // This part is application-specific and depends on how you communicate with the recipient.
    // Examples:
    // 1. Send via WebRTC Swarm:
    //    const swarmId = this.mVMContext.getMainSwarmID(); // Or another specific swarm
    //    const success = this.mVMContext.getSwarmsManager.sendData(
    //        transmissionToken.getPackedData(),
    //        recipientId, // Target the specific peer
    //        swarmId
    //    );
    //    if (success) { console.log("TT sent via swarm."); } else { console.error("Failed to send TT via swarm."); }

    // 2. Send via direct P2P connection (if available)
    // 3. Send via a centralized intermediary (if applicable to your dApp)

    this.showSuccess(`Transmission Token for ${valueAtto} Atto generated. Delivery mechanism required.`);
}

7.6. UI Updates based on Channel State

Keep the UI synchronized with the latest known channel state.

// Inside MyDApp class

async handleChannelStateChange(event) {
    const channel = event.channel;
    const newState = event.newState;
    // const previousState = event.previousState; // Can be used for comparison if needed

    const poolIdStr = gTools.encodeBase58Check(channel.getID());
    const friendlyId = channel.getFriendlyID() || poolIdStr;

    console.log(`State change detected for channel: ${friendlyId}`);

    // Update UI elements associated with this channel
    this.updateChannelDisplay(poolIdStr, {
        accumulated: newState.accumulatedAssets, // For ingress channels (potential cash-out value)
        spendable: newState.spendableAssets, // For outgress channels (what can be sent now)
        availableOnChain: newState.availableAssets // Total value left according to last sync/update
    });
}

updateChannelDisplay(channelId, stateData) {
    // Example: Find UI elements and update their content
    const elemAccumulated = document.getElementById(`channel_${channelId}_accumulated`);
    const elemSpendable = document.getElementById(`channel_${channelId}_spendable`);
    const elemAvailable = document.getElementById(`channel_${channelId}_available`);

    if (elemAccumulated) elemAccumulated.innerText = `${gTools.attoToGNCStr(stateData.accumulated)} GNC`;
    if (elemSpendable) elemSpendable.innerText = `${gTools.attoToGNCStr(stateData.spendable)} GNC`;
    if (elemAvailable) elemAvailable.innerText = `${gTools.attoToGNCStr(stateData.availableOnChain)} GNC`;
}

8. Advanced Topics

This section explores some of the more intricate aspects of the State-Less Channels system, including its underlying security model, error handling, performance characteristics, and security considerations.

8.1. Sybil-Proofing Mechanics

A fundamental requirement for any decentralized incentivization system operating in an open network is resistance to Sybil attacks, where a single malicious entity creates numerous fake identities to gain disproportionate influence or rewards.

The GRIDNET OS State-Less Channels system achieves Sybil-proofing primarily through the design of its

reward function

and the inherent properties of the

path assurance protocols

(PA1, PA2, PA3) used for data propagation, as detailed comprehensively in our research [1].

  • Key Principles:

    • Investment-Based Rewards:

      The core reward mechanism ties potential earnings to the verifiable “stake” or investment represented by the value and depth of the Token Pools involved (specifically the ABI value used in the identity rating function e). Creating numerous low-value Sybil identities to participate in a path yields significantly lower expected rewards compared to using a single, well-funded identity.

    • Path Integrity:

      The path assurance mechanisms ensure that the sequence of intermediaries recorded in the Transmission Token’s journey (implicitly or explicitly depending on the protocol variant) cannot be easily tampered with without invalidating cryptographic checks performed during the on-chain cash-out (xTTEx).

    • Reward Function Design:

      The specific mathematical formulation of the reward function FA ensures that concentrating investment into a single identity for a given path maximizes potential reward compared to distributing the same total investment across multiple Sybil identities within that same path.

  • In Essence:

    While the system cannot prevent the creation of Sybil identities at the network level, it makes using them within the incentivized State-Less Channel data flows economically irrational for profit-maximizing agents.

  • Further Reading:

    For a rigorous mathematical proof and detailed breakdown of the algorithms and game-theoretical analysis, please refer to Section 7 (“Proof of sybil-proofness”) and Section 6 (“Reward function”, “Routing mechanism”) of the SPIDE research paper [1].

8.2. Error Handling

Developers should anticipate potential issues when working with off-chain systems and network interactions.

  • Invalid Transmission Tokens:

    • Cause:

      Malformed data, failed hash chain verification (indicating tampering or an incorrect sequence), invalid signature (on authenticated TTs).

    • Detection:

      The CStateLessChannel.validateTT() method will return 0n.

    • Handling:

      The receiving UI dApp should simply discard or ignore invalid tokens. Attempting to cash them out via xTTEx will fail on-chain.

  • Insufficient Funds:

    • Sending (Outgress):

      channel.getTTForPeer() or channel.getTTWorthValue() will return null. The dApp should check the return value and inform the user. They might need a “Bank Update” from their mobile app if sufficient value exists in the pool overall but not in currently pre-cached banks (channel.getLocallySpendableAssets() vs. channel.getTokenPool().getValueLeft()).

    • Cashing Out (Ingress):

      If a recipient tries to cash out a token representing more value than currently available in the bank on-chain (e.g., due to a race condition or delay in state update), the xTTEx command will fail during DSM execution.

  • Double Spends / Replays:

    • Off-Chain:

      channel.validateTT() will return 0n if the incoming token’s bankUsageDepth is less than or equal to the currently cached depth for that bank.

    • On-Chain:

      The xTTEx command inherently prevents double-spending by verifying the token’s bankUsageDepth against the authoritative state stored on the DSM. Any attempt to cash out a token representing already spent depth will be rejected by consensus.

  • Network Issues & Timeouts:

    • Requests sent via CVMContext (e.g., for synchronize() or cashOut()) involve network communication and may fail or time out.
    • Handling:

      JavaScript Promises returned by async API calls will reject. Methods returning simple success indicators (like synchronize()) will return false. UI dApps must implement standard error handling (try...catch for async/await, checking return values) and potentially implement retry logic or inform the user.

  • Synchronization Issues (Stale Cache):

    • Cause:

      The local CTokenPool cache within a CStateLessChannel might not reflect the absolute latest on-chain state if a cash-out occurred recently but the channel hasn’t been synced.

    • Effect:

      validateTT() might incorrectly validate a token that would be rejected on-chain, or getAccumulatedValue() might report a higher value than actually cashable. getTTForPeer() might fail even if funds were available on-chain.

    • Mitigation:

      Use getIsReadyForVerification to ensure initial data is loaded. Call channel.synchronize() periodically or before critical operations, especially cash-outs, if high accuracy is required. The CStateLessChannelsManager performs periodic background synchronization.

8.3. Performance and Scalability Considerations

The State-Less Channels system is designed for high performance and scalability compared to pure on-chain transactions.

  • Off-Chain Speed:

    Transmission Token validation (validateTT) and generation (getTT...) are purely local cryptographic operations (primarily hashing) and are extremely fast. The main latency is network delivery time between peers.

  • On-Chain Bottlenecks:

    The primary performance limitations are the frequency and cost of on-chain operations:

    • Token Pool Creation (genPoolEx): A one-time cost per pool, involving writing data to DFS.
    • Cashing Out (xTTEx): Requires an on-chain transaction, consuming ERG and subject to DSM throughput (TPS).
  • Optimizations:

    • Batching Cash-Outs:

      Recipients are incentivized to delay cashing out until a significant value is accumulated or the channel dimension is nearly depleted, reducing the frequency of on-chain transactions.

    • Multi-Dimensionality:

      Allows many parallel off-chain streams using a single pool, significantly increasing the effective off-chain TPS supported by a single on-chain pool registration.

    • State-Less Design:

      Reduces the need for constant peer-to-peer state synchronization messages compared to some other channel designs.

  • Developer Considerations:

    Design dApps to minimize unnecessary cash-outs. Choose an appropriate number of dimensions for M-DTPs based on expected concurrent interactions. Rely on the Manager’s autonomous features where possible.

8.4. Security

Security relies on a combination of cryptographic primitives, consensus rules, and operational security practices.

  • Mobile App Trust:

    The GRIDNET Token mobile app is the primary custodian of the user’s private keys and the critical MasterSeedHash for owned Token Pools. Its security is paramount. Compromise of the mobile app could lead to the loss of funds secured by M-DTPs generated from its MasterSeedHash.

  • QR Intent Security:

    While QR codes themselves are just data, the process involving them is designed for security. Sensitive operations initiated via QR require confirmation and cryptographic signing within the secure mobile app environment after the QR is scanned. The response from the mobile app back to the Core node is typically onion-routed and end-to-end encrypted.

  • Signature Verification:

    • Authenticated TTs: Provide non-repudiation and proof of origin from the pool owner. The signature is verified against the pool’s public key (if available/published). xTTEx on-chain performs this verification if a signature is present.
    • Unauthenticated TTs: Rely solely on the hash chain math and the DSM’s state tracking for validity regarding value and double-spending. They do not cryptographically prove origin from the pool owner.
  • Hash Chain Integrity:

    The security against fabricating tokens relies on the pre-image resistance and collision resistance of the underlying cryptographic hash function (e.g., SHA256).

  • DSM Consensus:

    The ultimate security against on-chain double-spending and invalid state transitions relies on the integrity and Sybil-resistance of the underlying GRIDNET OS consensus mechanism.

  • Full Node Honesty:

    For unauthenticated TTs, there’s a theoretical risk: if a malicious node (e.g., the one serving the recipient’s session) intercepts an unauthenticated TT before the legitimate recipient caches it out, and that node knows the recipient’s ID, it could attempt to cash it out to itself first. Using authenticated TTs or ensuring prompt cash-out by the recipient mitigates this specific, more complex attack vector. Standard TTs used for payments between distinct parties are usually unauthenticated for efficiency. Bank Updates must be authenticated.


9. Appendices

9.1. Glossary

  • Atto:

    The smallest indivisible unit of GRIDNET’s native currency (GBU). Used for precise value representation in Token Pools.

  • Bank (Dimension):

    An independent hash chain within a Multi-Dimensional Token Pool, used to manage a distinct off-chain payment stream.

  • Cash Out:

    The on-chain process of redeeming the value represented by off-chain Transmission Tokens, resulting in an update to the recipient’s on-chain GBU balance and the Token Pool’s state on the DSM.

  • Ceiling Hash (Final Hash):

    The final, publicly known hash value anchoring a specific Bank’s hash chain within a Token Pool, stored on the DSM.

  • CStateLessChannel:

    The JavaScript class representing a single State-Less Channel instance within the UI dApp environment, managing interaction with a specific Token Pool.

  • CStateLessChannelsManager:

    The JavaScript singleton class managing all State-Less Channel instances, handling events, synchronization, and autonomous operations within the UI dApp environment.

  • CVMContext:

    The central JavaScript singleton acting as the gateway between UI dApps and the underlying GRIDNET OS functionalities.

  • DFS (Decentralized File System):

    GRIDNET OS’s integrated, decentralized storage layer where Token Pool data files are stored.

  • DPT (Decentralized Processing Thread):

    An execution context within GRIDNET OS, associated with an IVR, responsible for running code (#GridScript).

  • DSM (Decentralized State Machine):

    The core consensus-driven engine of GRIDNET OS, responsible for processing transactions and maintaining the global state, including Token Pool data stored on DFS.

  • GBU (GRIDNET Basic Unit):

    The primary native currency/asset of the GRIDNET OS ecosystem.

  • GridScript:

    The specialized, Forth-like programming language used by GRIDNET Core nodes and DPTs to execute instructions and interact with the DSM.

  • IVR (Isolated VM Realm):

    A sandboxed execution environment associated with a DPT, operating on a copy of the System Trie (Private VM Realm) or directly affecting the main state (Global VM Realm in Commitment Mode).

  • M-DTP (Multi-Dimensional Token Pool):

    The core data structure for State-Less Channels, registered on-chain, containing multiple independent hash chains (Banks/Dimensions) derived from a single MasterSeedHash, representing a pre-funded store of value for off-chain payments.

  • MasterSeedHash:

    The high-entropy secret held by the Token Pool owner (usually in the Mobile App), used to generate all hashes (tokens) within all dimensions of an M-DTP.

    Must be kept secret.

  • Receipt ID:

    The unique identifier of an on-chain transaction (e.g., the sacrificial transaction used to fund a Token Pool).

  • Sacrificial Transaction:

    An on-chain transaction where the sender locks value, the receipt of which is then used to authorize the creation of a Token Pool of equivalent value.

  • SeedHash (Dimension Seed Hash):

    The starting secret hash for a specific Bank/Dimension’s hash chain, deterministically derived from the MasterSeedHash.

  • State-Less Channel:

    The logical off-chain payment channel facilitated by an M-DTP and the exchange of TTs, minimizing peer-to-peer state synchronization requirements during the off-chain phase.

  • TT (Transmission Token):

    The data structure (CTransmissionToken object) exchanged off-chain, representing a specific amount of value released from a specific Bank of an M-DTP. It contains the revealed hash and updated bank state information needed for verification and eventual cash-out.

  • Transit Pool:

    A conceptual term referring to the accumulated off-chain value represented by a sequence of TTs for a single bank since the last on-chain cash-out. Usually, only the latest TT is needed to represent the entire Transit Pool when cashing out.

  • Usage Depth:

    An integer value stored on-chain for each Bank, indicating how many tokens (hashes) have been successfully revealed and cashed out from that Bank’s hash chain. This prevents double-spending.

9.2. Enum Definitions (JavaScript)

These enums define constants used within the State-Less Channels API:

  • eChannelDirection

    : Defines the perspective of a channel relative to the local user.

    • ingress: The local user is the recipient of funds via this channel.
    • outgress: The local user owns the pool and sends funds via this channel.
    • both: Used for filtering, not typically assigned to a channel instance.
  • eTokenPoolStatus

    : Overall status of a Multi-Dimensional Token Pool.

    • active: The pool is operational and has spendable value.
    • depleted: All dimensions/banks within the pool have been fully cashed out on-chain.
    • banned: The pool has been marked as invalid or banned by the system (e.g., due to detected fraud).
  • eTokenPoolBankStatus

    : Status of an individual dimension/bank within a Token Pool.

    • active: The bank has unspent tokens.
    • depleted: All tokens in this specific bank have been cashed out on-chain.
  • eStateLessChannelsElementType

    : Used within the VM Meta-Data protocol to identify the type of channel-related payload.

    • token: Payload is a CTransmissionToken representing a standard payment/reward.
    • tokenPool: Payload is a CTokenPool object’s public data.
    • transitPool: (See Glossary/API clarification).
    • receipt: Payload contains details of an on-chain transaction receipt related to a channel operation.
    • bankUpdate: Payload is a CTransmissionToken specifically flagged as revealing pre-cached hashes for an Outgress channel.
  • eChannelLocalPingType

    : Used internally by CStateLessChannel.ping() to specify which timestamp to update.

    • update: General update timestamp.
    • lastUsed: Timestamp for when a TT was generated from the channel.
    • lastSync: Timestamp for when synchronize() was last initiated.
    • lastCashOut: Timestamp for when cashOut() was last initiated.

9.3. Relevant GridScript Commands

These are the low-level commands executed by the DSM, typically invoked via the JavaScript API wrappers:

  • genPoolEx:

    (Requires parameters on stack: OwnerID, ReceiptID, DimensionsCount, TokenValue, FriendlyID, DisarmedPoolData) Registers a new, pre-generated (disarmed) Multi-Dimensional Token Pool on the DFS, validating it against the provided sacrificial transaction receipt.

    • Wrapper: genpool (accepts inline parameters)
  • xTTEx:

    (Requires parameters on stack: BER-encoded Transmission Token, optional RewardeeID) Processes an off-chain Transmission Token for on-chain cash-out. Verifies the token against the Token Pool state on DFS, updates the bank’s usage depth, and credits the rewardee’s on-chain balance.

    • Wrapper: xtt (accepts inline parameters)
  • getPoolEx:

    (Requires TokenPool ID on stack) Retrieves the BER-encoded public data of a specified Token Pool from the DFS.

    • Wrapper: getPool (accepts inline parameters)

9.4. Links

  • Research Papers:

  • Code Examples:

    • Wallet UI dApp:

      [Link to GRIDNET OS GitHub Repository – Wallet dApp source] (Requires specific link once available) – Demonstrates receiving tokens, displaying accumulated value, and initiating cash-outs.

    • GridCraft – Illustrates how Transmission Tokens can be used to reward players for collecting dynamic Gold Veins in the ground.

  • Tutorials:


10. GRIDNET OS State-Less Channels Security Threat Model

This comprehensive security threat model analyzes the GRIDNET OS State-Less Channels system, focusing on its security architecture, potential attack vectors, and defensive mechanisms. The system employs multiple layers of security through cryptographic primitives, compartmentalization, and verification protocols to protect off-chain transactions.

10.1. Trust Boundaries & Security Zones

As illustrated in the first diagram, the system is divided into three distinct security zones:

High Security Zone (Mobile App)

  • Contains the most sensitive cryptographic material: MasterSeedHash and Dimension Seeds
  • Hardware-backed secure storage for private keys
  • Limited interface with other zones through controlled channels (QR Intents)

Medium Security Zone (Browser/UI dApp)

  • Receives only the necessary subset of hash tokens via Bank Updates
  • Maintains local cache of pool state (public metadata and limited revealed hashes)
  • Shadow DOM isolation for UI components

Public Zone (Blockchain/DSM)

  • Only contains fully public data: ceiling hashes, bank usage depths, pool metadata
  • Provides consensus validation for cash-out operations

The security architecture enforces strict information flow between zones, with higher security zones only revealing controlled subsets of data to lower security zones.

10.2. Reverse Hash Chain Security Model

A core security mechanism in the system is the reverse hash chain:

  • During pool creation, a sequence of hashes is generated in one direction:
    Hash_0 (Seed) → Hash_1 → Hash_2 → … → Hash_N (Final/Ceiling)
  • Only the Final Hash (Hash_N) is published publicly on the blockchain
  • For spending, hashes are revealed in reverse order (N-1, N-2, etc.)

The security property that makes this work is the one-way nature of cryptographic hash functions: given Hash_i, it’s computationally infeasible to derive Hash_{i-1}. This means:

  • Revealing Hash_i does NOT compromise Hash_{i-1}
  • Early hashes in the chain maintain their secrecy even as later hashes are revealed
  • Each revealed hash can be verified against the public ceiling hash

This enables secure, off-chain value transfer with on-chain anchoring.

10.3. Token Pool Compartmentalization

The system further enhances security through Multi-Dimensional Token Pools (M-DTPs):

  • Each pool has multiple independent banks/dimensions
  • Each bank has its own separate hash chain derived from the MasterSeedHash
  • The mobile app controls precisely which hash segments from which banks are revealed
  • UI dApp is only given access to specific hash segments needed for current operations

This compartmentalization ensures that:

  • Compromise of one bank doesn’t affect others
  • Only a limited subset of value is exposed to the medium-security browser environment
  • The browser environment never has access to the MasterSeedHash or dimension seeds
  • Risk is isolated to specific revealed hash segments

10.4. Attack Vectors & Threat Analysis

The threat model identifies five primary attack vectors:

Attack Vector 1: Mobile App Compromise

  • Threat: Extraction of MasterSeedHash or dimension seeds
  • Impact: Total compromise of all banks in affected token pools
  • Mitigations: Hardware-backed secure storage, biometric protection, limited export capability

Attack Vector 2: Browser/UI dApp Compromise

  • Threat: Extraction of revealed hashes from bank updates
  • Impact: Limited to already-revealed tokens in specific banks
  • Mitigations: Limited bank updates, shadow DOM isolation, request signing

Attack Vector 3: Replay Attacks

  • Threat: Reuse of previously revealed TTs to claim value multiple times
  • Impact: Double-spending of the same token value
  • Mitigations: On-chain bank usage depth tracking, validation in xTTEx execution

Attack Vector 4: Man-in-the-Middle

  • Threat: Intercepting TTs during off-chain transmission
  • Impact: Unauthorized party could attempt to cash out tokens
  • Mitigations: Optional TT recipient ID, authenticated TTs, secure transmission channels

Attack Vector 5: Cryptographic Attacks

  • Threat: Finding hash function collisions or preimages
  • Impact: Potential forgery of tokens
  • Mitigations: Strong cryptographic hash functions with high preimage resistance

10.5. Defense-in-Depth Model

The State-Less Channels system implements defense-in-depth with four security layers:

Layer 1: Cryptographic Primitives

  • One-way hash functions (SHA-256)
  • Public key cryptography for signatures
  • Reverse hash chains for secure revelation

Layer 2: Multi-Dimensional Structure

  • Multiple independent banks isolate risk
  • Limited bank depth exposure through controlled updates
  • Compartmentalized token pools

Layer 3: Security Domain Separation

  • Mobile app isolation of critical secrets
  • Shadow DOM segregation in browser
  • QR Intent protocol for secure cross-domain communication

Layer 4: Verification & Validation

  • On-chain depth tracking prevents double-spending
  • DSM consensus validation for all cash-outs
  • Optional TT signatures for authentication

10.6. Conclusion

The GRIDNET OS State-Less Channels system demonstrates a sophisticated security architecture that:

  • Compartmentalizes risk through multi-dimensional token pools
  • Minimizes trusted computing base by keeping critical secrets in secure hardware
  • Provides cryptographic guarantees through one-way hash functions
  • Prevents double-spending through on-chain depth tracking
  • Limits exposure by selective revelation of hash tokens

The core innovation of using reverse hash chains allows for secure off-chain value transfer while maintaining strong cryptographic guarantees about the security and integrity of the system, even if parts of it are compromised.

GRIDNET

Author

GRIDNET

Up Next

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *