Skip to main content
This guide will walk you through the process of writing a simple native Rust program (without Anchor dependencies) that increments a counter. You’ll learn how to deploy this program on Solana and interact with it using a Typescript test script.

Software Packages

This program is developed and tested with the following software packages. Other versions may also be compatible.

Quick Access

If you prefer to dive straight into the code:

Source Code: Native Rust Counter Program

Source Code: Typescript Test Script

Core Functionality

The program implements two main instructions:
  1. InitializeCounter: Initialize and sets the counter to 0 (called on Base Layer)
  2. IncreaseCounter: Increments the initialized counter by X amount (called on Base Layer or ER)
The program implements specific instructions for delegating and undelegating the counter:
  1. Delegate: Delegates counter from Base Layer to ER (called on Base Layer)
  2. CommitAndUndelegate: Schedules sync of counter from ER to Base Layer, and undelegates counter on ER (called on ER)
  3. Commit: Schedules sync of counter from ER to Base Layer (called on ER)
  4. Undelegate: Undelegates counter on the Base Layer (called on Base Layer through validator CPI)
Here’s the core structure of our program:
Your “Undelegate” instruction must have the exact discriminator. It is never called by you, instead the validator on the Base Layer will callback with a CPI into your program after undelegating your account on ER.

Delegating the Counter PDA

In order to delegate the counter PDA, and make it writable in an Ephemeral Rollup session, we need to add an instruction which internally calls the delegate_account function. delegate_account will CPI to the delegation program, which upon validation will gain ownership of the account. After this step, an ephemeral validator can start processing transactions on the counter PDA and propose state diff trough the delegation program.

Transaction (Base Layer): Delegate

Inspect transactions details on Solana Explorer

Committing while the PDA is delegated

The ephemeral runtime allows committing the state of the PDA while it is delegated. This is done by building a MagicIntentBundleBuilder with the commit intent.

Transaction (ER): Commit

Inspect transaction details on Solana Explorer

Transaction (Base layer): Commit

Inspect transaction details on Solana Explorer

Undelegating the PDA

Undelegating the PDA is done by building a MagicIntentBundleBuilder with the commit_and_undelegate intent as part of some instruction. This commits the latest state and returns ownership of the PDA to the owner program. After undelegating and finalizing the state, the validator will create a callback CPI into undelegate on the base layer.

Transaction (ER): Undelegate

Inspect transaction details on Solana Explorer

Transaction (Base layer): Undelegate

Inspect transaction details on Solana Explorer

Testing the program

Build valid transactions that calls your program instructions for delegation and undelegation. The complete test for this project can be found in the Typescript Test Script.

Test delegation transaction

Create a instruction with the right order and attributes of accounts, and the instruction discriminator for delegation of your program. Send the transaction with the instruction to Base Layer (Solana) network.

Transaction (Base Layer): Delegate

Inspect transactions details on Solana Explorer

Test commit transaction

Create a instruction with the right order and attributes of accounts, and the instruction discriminator for commit of your program. Send the transaction with the instruction to ER network.

Transaction (ER): Commit

Inspect transaction details on Solana Explorer

Transaction (Base layer): Commit

Inspect transaction details on Solana Explorer

Test undelegation transaction

Create a instruction with the right order and attributes of accounts, and the instruction discriminator for undelegation of your program. Send the transaction with the instruction to ER network.

Transaction (ER): Undelegate

Inspect transaction details on Solana Explorer

Transaction (Base layer): Undelegate

Inspect transaction details on Solana Explorer

Ephemeral Endpoint Configuration

To interact with the Ephemeral Rollup session, you need to configure the appropriate endpoint:
  • For devnet, use the following ephemeral endpoint: https://devnet.magicblock.app
  • For mainnet, please reach out to the MagicBlock team to receive the appropriate endpoint.
  • For localhost, download, install, and run the ephemeral validator locally with the appropriate environment variables.
Make sure to update your client configuration to use the correct endpoint based on your development or production environment.
These public RPC endpoints are currently free and supported for development:
Magic Router Devnet: https://devnet-router.magicblock.app
Solana Devnet: https://api.devnet.solana.com
ER Devnet (Asia): https://devnet-as.magicblock.app
ER Devnet (EU): https://devnet-eu.magicblock.app
ER Devnet (US): https://devnet-us.magicblock.app
TEE Devnet: https://devnet-tee.magicblock.app/
Find out more details here .

Source Code: Native Rust Counter Program

Source Code: Typescript Test Script