Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/magicblock-labs/magicblock-engine-examples/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The TypeScript SDK provides functions and utilities to interact with MagicBlock Ephemeral Rollups from client applications. It includes delegation helpers, PDA derivation, connection management, and Bolt ECS integration.

Installation

npm install @magicblock-labs/ephemeral-rollups-sdk
For Bolt ECS applications:
npm install @magicblock-labs/bolt-sdk

Core Exports

Constants

import { 
  DELEGATION_PROGRAM_ID,
  MAGIC_CONTEXT_ID,
  MAGIC_PROGRAM_ID
} from "@magicblock-labs/ephemeral-rollups-sdk";
DELEGATION_PROGRAM_ID
PublicKey
The program ID of the delegation program used to delegate accounts to Ephemeral Rollups
MAGIC_PROGRAM_ID
PublicKey
The program ID of the magic program used for committing accounts from ER back to Solana
MAGIC_CONTEXT_ID
PublicKey
The magic context account required for commit operations

Connection Management

Setting up Connections

Establish separate connections for Solana base layer and Ephemeral Rollups:
import { Connection } from "@solana/web3.js";

// Base layer connection (Solana)
const connectionBaseLayer = new Connection(
  "https://api.devnet.solana.com",
  { wsEndpoint: "wss://api.devnet.solana.com" }
);

// Ephemeral Rollup connection
const connectionEphemeralRollup = new Connection(
  "https://devnet-as.magicblock.app/",
  { wsEndpoint: "wss://devnet-as.magicblock.app/" }
);

PDA Helpers

delegationRecordPdaFromDelegatedAccount

Derives the delegation record PDA for a delegated account.
import { delegationRecordPdaFromDelegatedAccount } from "@magicblock-labs/ephemeral-rollups-sdk";

const delegationRecord = delegationRecordPdaFromDelegatedAccount(counterPda);
delegatedAccount
PublicKey
required
The account being delegated
delegationRecord
PublicKey
The derived delegation record PDA

delegationMetadataPdaFromDelegatedAccount

Derives the delegation metadata PDA for a delegated account.
import { delegationMetadataPdaFromDelegatedAccount } from "@magicblock-labs/ephemeral-rollups-sdk";

const delegationMetadata = delegationMetadataPdaFromDelegatedAccount(counterPda);
delegatedAccount
PublicKey
required
The account being delegated
delegationMetadata
PublicKey
The derived delegation metadata PDA

delegateBufferPdaFromDelegatedAccountAndOwnerProgram

Derives the delegation buffer PDA for a delegated account and its owner program.
import { delegateBufferPdaFromDelegatedAccountAndOwnerProgram } from "@magicblock-labs/ephemeral-rollups-sdk";

const delegationBuffer = delegateBufferPdaFromDelegatedAccountAndOwnerProgram(
  counterPda,
  PROGRAM_ID
);
delegatedAccount
PublicKey
required
The account being delegated
ownerProgram
PublicKey
required
The program that owns the delegated account
delegationBuffer
PublicKey
The derived delegation buffer PDA

Delegation Instructions

While programs typically handle delegation via CPI, you can construct delegation instructions manually for testing or custom flows.

Manual Delegation Example

import {
  Transaction,
  TransactionInstruction,
  SystemProgram,
  sendAndConfirmTransaction
} from "@solana/web3.js";
import {
  DELEGATION_PROGRAM_ID,
  delegationRecordPdaFromDelegatedAccount,
  delegationMetadataPdaFromDelegatedAccount,
  delegateBufferPdaFromDelegatedAccountAndOwnerProgram
} from "@magicblock-labs/ephemeral-rollups-sdk";

const tx = new Transaction();

// Build the delegate instruction
const keys = [
  // Payer
  {
    pubkey: userKeypair.publicKey,
    isSigner: true,
    isWritable: true,
  },
  // System Program
  {
    pubkey: SystemProgram.programId,
    isSigner: false,
    isWritable: false,
  },
  // Account to delegate
  {
    pubkey: counterPda,
    isSigner: false,
    isWritable: true,
  },
  // Owner Program
  {
    pubkey: PROGRAM_ID,
    isSigner: false,
    isWritable: false,
  },
  // Delegation Buffer
  {
    pubkey: delegateBufferPdaFromDelegatedAccountAndOwnerProgram(
      counterPda,
      PROGRAM_ID
    ),
    isSigner: false,
    isWritable: true,
  },
  // Delegation Record
  {
    pubkey: delegationRecordPdaFromDelegatedAccount(counterPda),
    isSigner: false,
    isWritable: true,
  },
  // Delegation Metadata
  {
    pubkey: delegationMetadataPdaFromDelegatedAccount(counterPda),
    isSigner: false,
    isWritable: true,
  },
  // Delegation Program
  {
    pubkey: DELEGATION_PROGRAM_ID,
    isSigner: false,
    isWritable: false,
  },
];

const delegateIx = new TransactionInstruction({
  keys: keys,
  programId: PROGRAM_ID,
  data: Buffer.from("02", "hex"), // Your program's delegate discriminator
});

tx.add(delegateIx);
const txHash = await sendAndConfirmTransaction(
  connectionBaseLayer,
  tx,
  [userKeypair],
  { skipPreflight: true, commitment: "confirmed" }
);

Commitment Operations

GetCommitmentSignature

Waits for and returns the base layer commitment signature after committing state from ER.
import { GetCommitmentSignature } from "@magicblock-labs/ephemeral-rollups-sdk";

// After sending a commit transaction on ER
const txHash = await sendAndConfirmTransaction(
  connectionEphemeralRollup,
  commitTx,
  [userKeypair]
);

// Wait for the commitment on base layer
const txCommitSignature = await GetCommitmentSignature(
  txHash,
  connectionEphemeralRollup
);

console.log(`Base layer commit signature: ${txCommitSignature}`);
txHash
string
required
The transaction hash of the commit transaction sent on the Ephemeral Rollup
connection
Connection
required
The Ephemeral Rollup connection instance
commitSignature
string
The transaction signature on the base layer Solana chain

Commit Transaction Example

import {
  Transaction,
  TransactionInstruction,
  sendAndConfirmTransaction
} from "@solana/web3.js";
import {
  MAGIC_PROGRAM_ID,
  MAGIC_CONTEXT_ID,
  GetCommitmentSignature
} from "@magicblock-labs/ephemeral-rollups-sdk";

const tx = new Transaction();
const keys = [
  // Payer
  {
    pubkey: userKeypair.publicKey,
    isSigner: true,
    isWritable: true,
  },
  // Account to commit
  {
    pubkey: counterPda,
    isSigner: false,
    isWritable: true,
  },
  // Magic Program
  {
    pubkey: MAGIC_PROGRAM_ID,
    isSigner: false,
    isWritable: false,
  },
  // Magic Context
  {
    pubkey: MAGIC_CONTEXT_ID,
    isSigner: false,
    isWritable: true,
  }
];

const commitIx = new TransactionInstruction({
  keys: keys,
  programId: PROGRAM_ID,
  data: Buffer.from("04", "hex"), // Commit instruction discriminator
});

tx.add(commitIx);
const txHash = await sendAndConfirmTransaction(
  connectionEphemeralRollup,
  tx,
  [userKeypair],
  { skipPreflight: true, commitment: "confirmed" }
);

// Wait for base layer confirmation
const txCommitSgn = await GetCommitmentSignature(
  txHash,
  connectionEphemeralRollup
);
console.log(`Committed to base layer: ${txCommitSgn}`);

Bolt SDK (ECS)

For Bolt Entity Component System applications, use the Bolt SDK for specialized ECS operations.

Installation

npm install @magicblock-labs/bolt-sdk

Imports

import {
  InitializeNewWorld,
  AddEntity,
  InitializeComponent,
  ApplySystem,
  FindComponentPda,
  createDelegateInstruction,
  createUndelegateInstruction,
  DELEGATION_PROGRAM_ID
} from "@magicblock-labs/bolt-sdk";

ApplySystem

Executes a system on entities with specified components in the Bolt ECS framework.
import { ApplySystem } from "@magicblock-labs/bolt-sdk";

const applySystem = await ApplySystem({
  authority: provider.wallet.publicKey,
  world: worldPda,
  entities: [
    {
      entity: entityPda,
      components: [{ componentId: counterComponent.programId }],
    },
  ],
  systemId: systemIncrease.programId,
});

const tx = applySystem.transaction;
const txSign = await providerEphemeralRollup.sendAndConfirm(
  tx,
  [],
  { skipPreflight: true }
);
authority
PublicKey
required
The wallet with authority to execute the system
world
PublicKey
required
The world PDA in which the system operates
entities
Array<{ entity: PublicKey, components: Array<{ componentId: PublicKey }> }>
required
Array of entities and their components that the system will operate on
systemId
PublicKey
required
The program ID of the system to execute
transaction
Transaction
The constructed transaction ready to be signed and sent

FindComponentPda

Finds the PDA for a component attached to an entity.
import { FindComponentPda } from "@magicblock-labs/bolt-sdk";

const counterPda = FindComponentPda({
  componentId: counterComponent.programId,
  entity: entityPda,
});
componentId
PublicKey
required
The program ID of the component
entity
PublicKey
required
The entity PDA
componentPda
PublicKey
The derived component PDA

createDelegateInstruction

Creates an instruction to delegate a Bolt component to an Ephemeral Rollup.
import { createDelegateInstruction } from "@magicblock-labs/bolt-sdk";

const counterPda = FindComponentPda({
  componentId: counterComponent.programId,
  entity: entityPda,
});

const delegateIx = createDelegateInstruction({
  entity: entityPda,
  account: counterPda,
  ownerProgram: counterComponent.programId,
  payer: provider.wallet.publicKey,
});

const tx = new anchor.web3.Transaction().add(delegateIx);
const txSign = await provider.sendAndConfirm(tx);
entity
PublicKey
required
The entity that owns the component
account
PublicKey
required
The component account to delegate
ownerProgram
PublicKey
required
The component’s program ID
payer
PublicKey
required
The account paying for the delegation
instruction
TransactionInstruction
The delegation instruction

createUndelegateInstruction

Creates an instruction to undelegate a Bolt component from an Ephemeral Rollup.
import { createUndelegateInstruction } from "@magicblock-labs/bolt-sdk";

const counterComponentPda = FindComponentPda({
  componentId: counterComponent.programId,
  entity: entityPda,
});

const undelegateIx = createUndelegateInstruction({
  payer: provider.wallet.publicKey,
  delegatedAccount: counterComponentPda,
  componentPda: counterComponent.programId,
});

let tx = new anchor.web3.Transaction().add(undelegateIx);
const txSign = await providerEphemeralRollup.sendAndConfirm(tx);
payer
PublicKey
required
The account paying for the undelegation
delegatedAccount
PublicKey
required
The component account to undelegate
componentPda
PublicKey
required
The component’s program ID
instruction
TransactionInstruction
The undelegation instruction

Complete Example

Here’s a complete workflow demonstrating delegation, execution on ER, and undelegation:
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import {
  DELEGATION_PROGRAM_ID,
  MAGIC_PROGRAM_ID,
  MAGIC_CONTEXT_ID,
  delegationRecordPdaFromDelegatedAccount,
  delegationMetadataPdaFromDelegatedAccount,
  delegateBufferPdaFromDelegatedAccountAndOwnerProgram,
  GetCommitmentSignature
} from "@magicblock-labs/ephemeral-rollups-sdk";

// Setup connections
const baseConnection = new Connection("https://api.devnet.solana.com");
const erConnection = new Connection("https://devnet-as.magicblock.app/");

const userKeypair = Keypair.generate();
const [counterPda] = PublicKey.findProgramAddressSync(
  [Buffer.from("counter"), userKeypair.publicKey.toBuffer()],
  PROGRAM_ID
);

// 1. Delegate to ER (on base layer)
const delegateTx = await buildDelegateTransaction(
  userKeypair.publicKey,
  counterPda,
  PROGRAM_ID
);
const delegateSig = await sendAndConfirmTransaction(
  baseConnection,
  delegateTx,
  [userKeypair]
);

// 2. Execute transactions on ER
const incrementTx = await buildIncrementTransaction(
  userKeypair.publicKey,
  counterPda
);
const incrementSig = await sendAndConfirmTransaction(
  erConnection,
  incrementTx,
  [userKeypair]
);

// 3. Commit and undelegate (on ER)
const commitTx = await buildCommitAndUndelegateTransaction(
  userKeypair.publicKey,
  counterPda
);
const commitSig = await sendAndConfirmTransaction(
  erConnection,
  commitTx,
  [userKeypair]
);

// 4. Wait for base layer commitment
const baseSig = await GetCommitmentSignature(commitSig, erConnection);
console.log(`State committed to base layer: ${baseSig}`);

Network Endpoints

Devnet

  • Base Layer: https://api.devnet.solana.com (wss: wss://api.devnet.solana.com)
  • Ephemeral Rollups: https://devnet-as.magicblock.app/ (wss: wss://devnet-as.magicblock.app/)

Localnet

When running against localnet, you may need to include the validator identity as a remaining account:
const remainingAccounts = connection.rpcEndpoint.includes("localhost") ||
                          connection.rpcEndpoint.includes("127.0.0.1")
  ? [
      {
        pubkey: new PublicKey("mAGicPQYBMvcYveUZA5F5UNNwyHvfYh5xkLS2Fr1mev"),
        isSigner: false,
        isWritable: false,
      },
    ]
  : [];

Build docs developers (and LLMs) love