Skip to the content.

Purpose

This documentation is intended for developers and users of zela.io and serves as a central reference for understanding how to work with the platform.

The goal of this documentation is to:

The documentation focuses on practical usage and operational concepts rather than internal implementation details. It is suitable for both new users onboarding to zela.io and experienced users looking for a consistent reference.


Introduction

zela.io is a platform for deploying and executing Solana procedures in a controlled and scalable environment.

Zela lets you send a procedure to run next to the current Solana block producer, so your application gets the full workflow outcome in a single call instead of many separate RPC requests.

Think of it as a Solana-compatible JSON-RPC layer where you can deploy custom procedures that run in Zela’s execution environment and interact with Solana RPC nodes on your behalf.

In Zela terminology, a procedure is a unit of user code that implements the CustomProcedure trait and can be invoked via JSON-RPC.

Benefits


Architecture Overview

zela.io is built as a set of specialized modules that work together to build, execute, and expose procedures. Each component has a clear responsibility, which helps keep the platform reliable, scalable, and easier to operate. At a high level, the platform consists of the following core components:

Builder

The Builder module is responsible for turning source code into WebAssembly procedure artifacts.

It handles:

Only successfully built procedures can be executed by the platform.

Executor

The Executor module is responsible for running built procedures in an isolated execution environment.

It handles:

The Executor ensures that procedures run in a controlled and predictable manner and that they run as fast as possible.

The Executor isn’t a singular instance. It is deployed in multiple geographical locations corresponding to Solana hotspots - places where existing Solana traffic is concentrated. This aims to that your procedures run as close as possible to the Solana Leaders and receive the most up-to-date state.

Solana proxy

The Solana proxy module provides access and smart selection of upstream Solana RPC nodes.

It is used to:

The Solana proxy enables that each time a procedure requires data it reaches out to the upstream with the lowest round-trip latency from the Executor server.

Dashboard & API Layer

The Dashboard and API layer provide the main interface to the zela.io platform.

They are used for:

This layer is designed to support both human users (via the Dashboard UI) and programmatic access (via APIs).

Component Interaction (High Level)

At a high level, the interaction flow is as follows:

  1. A procedure source is configured via the Dashboard.
    1. The source points to a branch in a GitHub repository.
    2. This configuration is stored in the Core service.
  2. The Builder compiles and validates the procedure source.
    1. The Builder is able to access the GitHub repository thanks to access granted through our GitHub App.
    2. The build is performed in a containerized environment and the build logs are available in the Dashboard.
    3. The output WebAssembly artifact is stored in our database.
  3. A successful build becomes available for execution.
    1. The identifier is the git commit hash, so you always know which source code you are running.
    2. The JSON-RPC method name is always zela.PROCEDURE_NAME#COMMIT_HASH together with an appropriate JWT authentication token.
  4. The Executor runs the procedure on demand.
    1. Performing a JSON-RPC call to the executor triggers a load to cache.
    2. The WebAssembly artifact is loaded and compiled to native code on the Executor itself.
  5. The Dashboard exposes logs and metadata.
    1. Runtime logs are available for each revision.

Deploying a Procedure

This section describes the high-level steps required to deploy a procedure on zela.io, from source configuration to a successful build.

Creating a Procedure Source

To deploy a procedure, a source must first be created within a project. Your first and default project is created during the onboarding.

A source defines how WASM artifacts are materialized in Zela. We support automatic builds from GitHub and manual uploads of WASM artifacts.

For GitHub the configuration includes:

The Git repository must be a Rust Cargo workspace or a crate. Linking a GitHub repository is optional.

Once a source is created, it becomes the basis for building and deploying procedures on the platform.

Triggering a Build

After a source is configured, a build can be triggered to compile and validate the procedure.

Builds are triggered on push events to your GitHub repository (filtered by the configured branch) and automatically when creating the source in the Dashboard UI. If you have not linked a GitHub repository to your procedure source see Manual upload below.

Each build is tracked independently and has a clearly defined lifecycle.

Build Lifecycle

Every build progresses through a set of well-defined states:

Only builds that reach the Success state can be used by the Executor.

Builds can fail for multiple reasons. Review the build logs to see if the error is related to the source code or something else.

To avoid redundant work, builds for a git commit hash that has already been successfully built may be automatically canceled. In that case, the previously successful build is reused.

Manual upload

Each procedure source can also be used without providing source code by uploading build WASM artifacts directly to Zela.

We expect a WASM Component that fulfills this WIT world. For Rust we provide the zela-std crate, then build for the wasm32-wasip2 target and cdylib crate type. Check out our zela-demo repository to help you get started.

Once you have built your WASM artifact, you can upload it to Zela using the Zela dashboard by editing your procedure or through our API:

curl -f \
	-H "authorization: Bearer $ZELA_JWT" -H 'content-type: application/wasm' \
	--data-binary '@target/wasm32-wasip2/release/hello_world.wasm' \
	"https://core.zela.io/procedures/$ZELA_PROCEDURE/wasm?project=$ZELA_PROJECT&file_name=hello_world.wasm"

To obtain the ZELA_JWT use one of your project keys as described in the Execution section.

For further inspiration take a look at our demo GitHub Actions workflow file which implements manual upload.

After a Successful Build

Once a build completes successfully:

From this point, the procedure can be executed and monitored through the platform.


Execution & Debugging

This section describes how procedures are executed on zela.io and how common issues can be investigated and resolved.

Executing a Procedure

A procedure becomes available for execution once it has been built successfully.

Procedures are executed by sending a JSON-RPC HTTP request to the executor URL - https://executor.zela.io.

The first step of this process is obtaining a JWT representing access to your project. The JWTs are short-lived but can be generated asynchronously and used when calling the RPC.

To obtain the JWT perform a client_credentials OAuth2 flow against our Identity Provider with one of your Project keys. You can generate and inspect a project key in the Dashboard.

curl --header 'Authorization: Basic base64($key_client_id:$key_secret)' --data 'grant_type=client%5Fcredentials' --data 'scope=zela%2Dexecutor%3Acall' 'https://auth.zela.io/realms/zela/protocol/openid-connect/token'

Once you have obtained the access_token from the response use it as Bearer authentication for your JSON-RPC calls as follows:

curl --header 'authorization: Bearer $jwt' --header 'Content-Type: application/json' --data $'{ "jsonrpc": "2.0", "id": 1, "method": "zela.zela-demo#32902637cc96f8d95ee436d1e9ea30e49abd06b0", "params": { "first_number": 123, "second_number": 456 }}' 'https://executor.zela.io'

This would execute procedure zela-demo build commit hash 32902637cc96f8d95ee436d1e9ea30e49abd06b0 from the project tied to the JWT. If the Executor does not have the procedure cached it will take a few seconds to load it into memory. Afterwards it will use the cached procedure and apply your configured concurrency limits (as set before in the Onboarding or Dashboard).

Using Logs for Debugging

Logs are the primary source for debugging issues on zela.io.

Typical use cases include:

To emit logs from your procedures use the log crate integration enabled in our zela-std crate. Note that the default maximum log level is set to INFO, but can be configured in your procedure at compile time.

Common Debugging Steps

When a procedure does not behave as expected, the following steps are recommended:

  1. Ensure the source configuration (repository, branch, procedure name) is correct.
  2. Verify that the latest build completed successfully.
  3. Review build logs for errors or warnings.
  4. Inspect execution logs for runtime failures.
  5. Confirm that input parameters are valid and correctly formatted.
    1. If you are using solana-client RpcClient::send please note that the client requires the parameters to be an array. If you wish to use the RpcClient to also interact with zela.io you can wrap your input parameters in an array:

       impl CustomProcedure for YourProcedure {
       	type Params = [YourParams; 1];
       	// ...
              
       	async fn run(params: Self::Params) -> Result<Self::SuccessData, RpcError<Self::ErrorData>> {
       		let [params] = params;
       		// ... your code
       	}
       }
      

Support

If you have any further questions or need help with anything don’t hesitate to contact us at support@zela.io