> ## Documentation Index
> Fetch the complete documentation index at: https://magicblock-42-dhruvja-docs-navigation-restructure.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Ephemeral SPL Token Quickstart

> Delegate an SPL token account to an Ephemeral Rollup, transfer on the ER, and withdraw back to the base layer — with the ephemeral-rollups-sdk.

***

<Tip>
  **Building with an AI coding agent?** Install the MagicBlock Dev Skill to give your agent MagicBlock-specific patterns — delegation flows, Magic Actions, cranks, VRF, and more.

  Quick install for Claude Code:

  ```bash theme={null}
  npx add-skill https://github.com/magicblock-labs/magicblock-dev-skill
  ```

  Using Cursor, Codex, Windsurf, Cline, or another agent? See the [AI Dev Skill](/pages/overview/additional-information/ai-dev-skill) page for all install targets.
</Tip>

### Quick Access

Check out example:

<CardGroup cols={2}>
  <Card title="GitHub" icon="github" href="https://github.com/magicblock-labs/magicblock-engine-examples/tree/main/spl-tokens" iconType="duotone">
    SPL Tokens Anchor Implementation
  </Card>

  <Card title="Live Example App" icon="coins" href="https://one.magicblock.app/" iconType="duotone">
    Try private payments
  </Card>
</CardGroup>

<Note>
  Snippets target `@magicblock-labs/ephemeral-rollups-sdk` **v0.14.3** with the legacy-vault path. The
  idempotent-shuttle path targets v0.15.3 — keep the same path across `delegateSpl` / `undelegateIx` /
  `withdrawSpl` within one lifecycle.
</Note>

***

## Step-By-Step Guide

Move SPL tokens through the full lifecycle against the Ephemeral SPL Token program
`SPLxh1LVZzEkX99H6rqYizhytLWPZVV296zyYDPagv2` — [delegate](/pages/ephemeral-rollups-ers/introduction/ephemeral-accounts), transact on the [ER](/pages/ephemeral-rollups-ers/introduction/ephemeral-rollup), then settle back to
Solana:

<Steps>
  <Step title={<a href="#1-delegate">Delegate the token account</a>}>
    Delegate an owner's balance to a validator on the base layer. The first delegation for a mint
    creates the shared Global Vault.
  </Step>

  <Step title={<a href="#2-transfer">Transfer on the ER</a>}>
    Move tokens between eATAs inside the rollup — public or private.
  </Step>

  <Step title={<a href="#3-undelegate">Undelegate & commit</a>}>
    Undelegate on the ER and wait for the commit back to base.
  </Step>

  <Step title={<a href="#4-withdraw">Withdraw to base</a>}>
    Move the balance out of the Global Vault to a base-layer token account.
  </Step>
</Steps>

***

## Ephemeral SPL Token Example

The following software packages may be required, other versions may also be compatible:

| Software   | Version | Installation Guide                                              |
| ---------- | ------- | --------------------------------------------------------------- |
| **Solana** | 3.1.9   | [Install Solana](https://docs.anza.xyz/cli/install)             |
| **Rust**   | 1.89.0  | [Install Rust](https://www.rust-lang.org/tools/install)         |
| **Anchor** | 1.0.2   | [Install Anchor](https://www.anchor-lang.com/docs/installation) |
| **Node**   | 24.10.0 | [Install Node](https://nodejs.org/en/download/current)          |

Install the SDK:

```bash theme={null}
yarn add @magicblock-labs/ephemeral-rollups-sdk@0.14.3
```

### Code Snippets

<Tabs>
  <Tab title="1. Delegate">
    `delegateSpl` delegates an owner's balance to a validator. The first delegation for a mint creates
    the shared Global Vault (`initVaultIfMissing: true`); later ones reuse it. Send on the **base
    layer**, and fund the rent sponsor (`deriveRentPda()`) before delegating.

    ```typescript theme={null}
    // Legacy vault flow — keep the same idempotent setting across
    // delegateSpl / undelegateIx / withdrawSpl within one lifecycle.
    const delegateOpts = { validator, idempotent: false as const, payer: admin.publicKey };

    const ixs = await delegateSpl(owner.publicKey, mint.publicKey, amount, {
      ...delegateOpts,
      initVaultIfMissing, // true for the first owner of this mint, false after
    });

    await provider.sendAndConfirm(
      new anchor.web3.Transaction().add(...ixs),
      [owner, admin],
      { commitment: "confirmed", skipPreflight: true },
    );
    ```

    [⬆️ Back to Top](#code-snippets)
  </Tab>

  <Tab title="2. Transfer">
    `transferSpl` moves tokens between eATAs inside the rollup. Send on the **ephemeral** provider. Set
    `visibility: "private"` for a private payment or `"public"` for a normal fast transfer.

    ```typescript theme={null}
    // Delegation confirms on base before the ER clones the account —
    // poll the ER view before transferring.
    await waitForErTokenAccount(ata, expectedAmount);

    const transferIxs = await transferSpl(
      recipientA.publicKey,
      recipientB.publicKey,
      mint.publicKey,
      2n,
      { visibility: "public", fromBalance: "ephemeral", toBalance: "ephemeral" },
    );

    await providerEphemeralRollup.sendAndConfirm(
      new anchor.web3.Transaction().add(...transferIxs),
      [recipientA],
      { commitment: "confirmed", skipPreflight: true },
    );
    ```

    [⬆️ Back to Top](#code-snippets)
  </Tab>

  <Tab title="3. Undelegate">
    Undelegate each owner on the ER (one per transaction), then wait for the commit back to base with
    `GetCommitmentSignature` before withdrawing.

    ```typescript theme={null}
    const sgn = await providerEphemeralRollup.sendAndConfirm(
      new anchor.web3.Transaction().add(undelegateIx(owner.publicKey, mint.publicKey)),
      [owner],
      { commitment: "confirmed", skipPreflight: true },
    );

    // Wait for the commit back to base before withdrawing, or the withdraw
    // races the commit and fails with InvalidAccountOwner.
    const commit = await GetCommitmentSignature(sgn, providerEphemeralRollup.connection);
    await connection.confirmTransaction(commit, "confirmed");
    ```

    [⬆️ Back to Top](#code-snippets)
  </Tab>

  <Tab title="4. Withdraw">
    `withdrawSpl` moves the balance out of the Global Vault back to the owner's base-layer ATA.

    ```typescript theme={null}
    const withdrawIxs = await withdrawSpl(owner.publicKey, mint.publicKey, amount, {
      idempotent: false,
    });

    await provider.sendAndConfirm(
      new anchor.web3.Transaction().add(...withdrawIxs),
      [owner],
      { commitment: "confirmed" },
    );
    ```

    [⬆️ Back to Top](#code-snippets)
  </Tab>

  <Tab title="ER-aware program">
    To route the ER-side transfer through your own program instead of the SDK helper, add the
    `#[ephemeral]` attribute — the instruction is a plain SPL Token CPI. See
    [Smart Contract Integration](/pages/ephemeral-spl-token/smart-contract-integration) for custody
    and PDA-signed transfers.

    ```rust theme={null}
    use anchor_lang::prelude::*;
    use anchor_spl::token::{self, Token, TokenAccount, Transfer as SplTransfer};
    use ephemeral_rollups_sdk::anchor::ephemeral;

    #[ephemeral]
    #[program]
    pub mod spl_tokens {
        use super::*;

        /// Transfer `amount` of SPL tokens from `from` to `to`.
        pub fn transfer(ctx: Context<TransferTokens>, amount: u64) -> Result<()> {
            require!(amount > 0, ErrorCode::InvalidAmount);
            let cpi_accounts = SplTransfer {
                from: ctx.accounts.from.to_account_info(),
                to: ctx.accounts.to.to_account_info(),
                authority: ctx.accounts.payer.to_account_info(),
            };
            let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts);
            token::transfer(cpi_ctx, amount)?;
            Ok(())
        }
    }
    ```

    [⬆️ Back to Top](#code-snippets)
  </Tab>
</Tabs>

<Note>
  **Run it locally:** `yarn` → `yarn build` → `yarn setup` (boots the local base + ER cluster; leave
  running) → `yarn test:local` in a second terminal.
</Note>

***

## Solana Explorer

Get insights about your transactions and accounts on Solana:

<CardGroup cols={2}>
  <Card title="Solana Explorer" icon="search" href="https://explorer.solana.com/" iconType="duotone">
    Official Solana Explorer
  </Card>

  <Card title="Solscan" icon="searchengin" href="https://solscan.io/" iconType="duotone">
    Explore Solana Blockchain
  </Card>
</CardGroup>

## Solana RPC Providers

Send transactions and requests through existing RPC providers:

<CardGroup cols={2}>
  <Card title="Solana" icon="star" href="https://solana.com/docs/references/clusters#on-a-high-level" iconType="duotone">
    Free Public Nodes
  </Card>

  <Card title="Helius" icon="sun" href="https://www.helius.dev/solana-rpc-nodes" iconType="duotone">
    Free Shared Nodes
  </Card>

  <Card title="Triton" icon="crystal-ball" href="https://triton.one/solana" iconType="duotone">
    Dedicated High-Performance Nodes
  </Card>
</CardGroup>

## Solana Validator Dashboard

Find real-time updates on Solana's validator infrastructure:

<CardGroup cols={2}>
  <Card title="Solana Beach" icon="wave" href="https://solanabeach.io/" iconType="duotone">
    Get Validator Insights
  </Card>

  <Card title="Validators App" icon="cloud-binary" href="https://www.validators.app/" iconType="duotone">
    Discover Validator Metrics
  </Card>
</CardGroup>

## Server Status

Subscribe to Solana's and MagicBlock's server status:

<CardGroup cols={2}>
  <Card title="Solana Status" icon="server" href="https://status.solana.com/" iconType="duotone">
    Subscribe to Solana Server Updates
  </Card>

  <Card title="MagicBlock Status" icon="heart-pulse" href="/pages/overview/additional-information/system-status" iconType="duotone">
    Subscribe to MagicBlock Server Status
  </Card>
</CardGroup>

***

## MagicBlock Products

<CardGroup cols={2}>
  <Card title="Ephemeral Rollup (ER)" icon="bolt" href="/pages/ephemeral-rollups-ers/how-to-guide/quickstart" iconType="duotone">
    Execute real-time, zero-fee transactions securely on Solana.
  </Card>

  <Card title="Private Ephemeral Rollup (PER)" icon="shield-check" href="/pages/private-ephemeral-rollups-pers/how-to-guide/quickstart" iconType="duotone">
    Protect sensitive data with compliance — built on top of Ephemeral Rollups.
  </Card>

  <Card title="Ephemeral SPL Token" icon="coins" href="/pages/ephemeral-spl-token/overview" iconType="duotone">
    Move SPL tokens at rollup speed — public or private transfers, swaps, and private payments for trading and DeFi apps.
  </Card>

  <Card title="Prediction Markets & Trading" icon="chart-line" href="/pages/solutions/prediction-markets" iconType="duotone">
    Combine real-time execution, session keys, token custody, price feeds, automation, and settlement.
  </Card>

  <Card title="Solana VRF" icon="dice" href="/pages/verifiable-randomness-functions-vrfs/introduction/solana-vrf" iconType="duotone">
    Add provably fair onchain randomness to games, raffles, and real-time apps.
  </Card>

  <Card title="Pricing Oracle" icon="waveform" href="/pages/tools/oracle/introduction" iconType="duotone">
    Access low-latency onchain price feeds for trading and DeFi.
  </Card>
</CardGroup>

***
