JamScript: Compose Like Smart Contracts, Scale Like Rollups, Build Like Web2 on JAM

JamScript is a language designed for building applications on JAM. It allows developers to build JAM applications in a way that feels close to traditional application development, without needing to understand JAM’s underlying mechanisms.

JamScript itself defines the language and application model, while the JamScript SDK provides supporting capabilities such as clients and Backend Interfaces. Ultimately, JamScript aims to introduce a new application paradigm on top of JAM: one that combines flexible composability with horizontal scalability.

Hello, JamScript

You do not need to understand how JAM works internally. A minimal Counter can be written as:

export class Counter {
  value: u64 = 0

  increment() {
    this.value += 1
  }

  get(): u64 {
    return this.value
  }
}

Then simply build and deploy it:

jams build
jams deploy

How a user operation is converted into JAM Work, how the final state transition is produced, how applications call each other, and how Refine and Accumulate are involved are all handled by the JamScript toolchain and application infrastructure. Developers do not need to deal with these underlying processes directly.

JamScript Application Model

Today, blockchain applications broadly follow two major paradigms: smart contracts and Rollups.

The main advantage of smart contracts is native atomic composability. Different applications run in the same environment, and one application can directly call another. But because they share the same execution and state environment, the system tends to grow continuously as more functionality and applications are added, eventually reaching scaling limits.

Rollups offer stronger independence and massive capacity expansion through independent blockspace. At the same time, however, they introduce fragmentation. When two applications live on different Rollups, composing them usually requires additional messaging, proofs, and asynchronous protocols, rather than the simple direct calls available between smart contracts.

JAM is a lower-level abstraction. A Service can write state into JAM and read the state of other Services. At the same time, large amounts of computation can be scaled in parallel through Cores.

This creates another possibility: applications can achieve scalability closer to parachains or Rollups, while remaining as easy to compose as smart contracts.

With this goal in mind, JamScript defines an application model on top of JAM. At its simplest, a JamScript Application can be understood in terms of three concepts: State, Action, and Ownership:

  • State: what the application stores.
  • Action: how the application state can change.
  • Ownership: who is authorized to initiate those changes.

There is, however, another important problem: state liveness.

JAM guarantees that State evolves correctly through Actions, but the state itself lives outside JAM. In traditional Rollups or parachains, this is typically guaranteed by infrastructure such as Rollup nodes or Sequencers.

But when the granularity moves from an entire chain down to an individual application, requiring every application to independently maintain this kind of infrastructure is fundamentally unsafe.

Although DA and Checkpoints can be used to recover state, recovery alone is far from sufficient.

If one application depends on another application whose complete state is no longer available, the problem does not affect only that application. It can cause the entire composed application system to lose liveness.

This is why we need an Application Backend to guarantee continuous visibility of complete application state and coordinate application execution.

There is also another problem. Applications interact through messages. If we want composability close to smart contracts, we need to answer one fundamental question:

How can a cross-Service operation succeed or fail as one complete action?

This is what MiniKernel is designed to solve.

MiniKernel

MiniKernel is a Service interaction runtime that is independent of the underlying message transport.

It adds an extremely thin execution layer around a Service, making messages emitted by that Service attributable.

Every message produced by a Service is deterministically exposed in an append-only manner and ultimately committed into that Service’s Message Root.

MiniKernel does not define how messages must be transported.

Messages may be propagated through SpecMsg, other messaging protocols, relay networks, or even multiple transport paths at the same time. The transport layer is only responsible for delivering messages to the target Service faster.

Unlike CoreVM or CorePlay, JamScript does not use a continuation model that spans multiple slots. This makes scheduling significantly simpler.

A call begins with a root Action, and all cross-Service calls, return values, and final results must complete within the same slot. State changes only take effect after the entire call chain succeeds. If any execution unit fails along the way, the entire call chain fails.

For developers, there is no need to understand how MiniKernel works internally. A swap can simply be expressed using await:

async swap(amount: u128) {
  const received = await pool.swap(amount)
  await token.transfer(msg.owner, received)
}

Application Backend

The JamScript SDK defines standard interfaces for interacting with an Application Backend, allowing a Backend to reliably serve JamScript Applications.

This does not require a strong additional trust assumption.

For complete-state visibility, the model is inherently 1-of-N: as long as at least one independent Provider still retains the complete state, the application can remain live.

For message relaying, the relay is only an accelerator and does not form part of the final security assumption.

We are particularly interested in large-scale, decentralized public Backends.

A Backend can provide state visibility, interaction acceleration, and a unified user experience for a large number of JamScript Applications. Users interact directly with the Backend and pay Gas to it, while the Backend handles efficiency and resource provisioning, hiding the underlying complexity from both developers and users.

The main responsibilities of a Backend include:

  • Transaction Ingress: For users, token.transfer(bob, 100) is simply a normal transaction. They do not need to understand the underlying JAM Service. The Application Backend can provide a unified transaction entry point and handle validation, nonces, ordering, queuing, and batching.

  • State & Proof: The Backend maintains the application’s immediate, complete, and trustworthy state, ensuring that the state of every application remains immediately available and preserving application liveness.

  • Message Relay: The Backend can provide low-latency message relaying for MiniKernel. Applications may optimistically use relayed messages and complete cross-Service call / await / return flows within the same slot. MiniKernel guarantees that a call chain either succeeds completely or fails completely.

    Messages actually emitted by a Service eventually form its Message Root. Off-chain checkers can use that root to verify whether the relay omitted, modified, or fabricated messages. When an error is detected, only the affected call chain is rolled back; in severe cases, the entire affected group is rolled back and penalties are applied.

    In other words, the relay is responsible for acceleration and does not need to be trusted. MiniKernel is responsible for consistency, while the Message Root provides the basis for error detection and correction.

Application Backends can support flexible operating models. The model most likely to see broad adoption is a Gas-based mechanism.

Finally, an Application Backend can provide many capabilities closer to applications and users, including Gas abstraction, Sponsored Transactions, privacy protection, ZK proving, indexing services, censorship-resistant transaction ingress, and different payment methods.

Ownership Abstraction

In traditional blockchains, cryptography and the chain itself are usually tightly coupled. Users must interact with the chain using a specific cryptographic system.

JAM does not require a global user account model, which creates a new design space.

We abstract this into the concept of Ownership. Applications no longer need to care which cryptographic system a user is using. Different cryptographic systems can all interact with a JamScript Application as first-class citizens.

In simple terms, JamScript natively supports different wallets, and even allows users to interact without a traditional Web3 wallet.

You can use Polkadot, EVM, Solana, and other Web3 wallets to interact with applications. You can also use social identities such as Matrix or Telegram to obtain control over an Ownership.

Ownership abstraction is a default capability in JamScript. Users do not need to think first about, “Which wallet should I use?”

Developers do not need to manually handle different signature schemes. They only need to declare:

auth: wallet()

The JamScript Runtime performs authorization verification at the Action boundary, and application code only needs to work with an already verified Owner.

Ownership abstraction is a native cryptographic primitive in JamScript. We will introduce it in more detail later.

Overall Architecture

The overall relationship between JamScript and the JamScript SDK can be understood as follows:

Progress

JamScript has already completed the most fundamental language, compilation, deployment, and single-Service Runtime path, and can now be used to develop and run simple JAM Applications.

Ownership Abstraction has been implemented and is now being further integrated into the toolchain and SDK.

The most important next steps are MiniKernel and a more complete Application Backend.

Our ultimate goal is to let JAM Applications achieve scalability close to Rollups while remaining as easy to compose as smart contracts — and, on top of that, enable entirely new capabilities.

GitHub: GitHub - ArcheLabs/JamScript: A TypeScript-like language and toolchain for building JAM services. · GitHub

Documentation: JamScript Overview | MiniJAM Documentation

Frontend SDK: https://www.npmjs.com/package/@jamscript/client