arcium-frontend

SKILL.md

Arcium Frontend Development

Guide for building encrypted Solana applications using Arcium.

When to Use This Skill

Use this skill when:

  • Building a new Arcium-powered frontend
  • Adding encrypted computations to existing apps
  • Integrating Solana wallet adapters
  • Deriving Arcium PDAs
  • Encrypting user inputs
  • Building and sending encrypted instructions
  • Troubleshooting Arcium-related errors

Required Dependencies

npm install @arcium-hq/client @coral-xyz/anchor @solana/web3.js

Environment Variables

Variable Required Default
ARCIUM_CLUSTER_OFFSET Yes
NEXT_PUBLIC_MXE_PROGRAM_ID Yes
NEXT_PUBLIC_RPC_URL No devnet

Core Flow

  1. Setup provider → Create Anchor provider from wallet
  2. Fetch MXE keygetMXEPublicKey(provider, programId)
  3. Generate offset → Random 8-byte computation offset
  4. Encrypt values → X25519 key exchange + RescueCipher
  5. Derive PDAs → MXE, cluster, computation, comp def accounts
  6. Build instruction → Encode discriminator + encrypted data
  7. Send transaction → Sign and submit with compute budget

Key Imports

import * as anchor from '@coral-xyz/anchor';
import { PublicKey, SystemProgram } from '@solana/web3.js';
import {
  getMXEPublicKey,
  getClusterAccAddress,
  getMXEAccAddress,
  getMempoolAccAddress,
  getExecutingPoolAccAddress,
  getComputationAccAddress,
  getCompDefAccAddress,
  getArciumAccountBaseSeed,
  getCompDefAccOffset,
  getArciumProgramId,
  x25519,
  RescueCipher,
  deserializeLE,
} from '@arcium-hq/client';

Encryption Pattern

// 1. Fetch MXE public key
const mxePublicKey = await getMXEPublicKey(provider, programId);

// 2. Generate ephemeral keypair
const privateKey = x25519.utils.randomPrivateKey();
const publicKey = x25519.getPublicKey(privateKey);

// 3. Derive shared secret
const sharedSecret = x25519.getSharedSecret(privateKey, mxePublicKey);

// 4. Encrypt values
const cipher = new RescueCipher(sharedSecret);
const nonce = nacl.randomBytes(16);
const values = [BigInt(10), BigInt(7), BigInt(5)];
const ciphertexts = cipher.encrypt(values, nonce);

PDA Derivation Pattern

// Cluster-based PDAs
const clusterOffset = 768109697; // from ARCIUM_CLUSTER_OFFSET
const clusterAccount = getClusterAccAddress(clusterOffset);
const mempoolAccount = getMempoolAccAddress(clusterOffset);
const executingPool = getExecutingPoolAccAddress(clusterOffset);

// Program-based PDAs
const mxeAccount = getMXEAccAddress(programId);
const computationOffset = new anchor.BN(nacl.randomBytes(8), 'le');
const computationAccount = getComputationAccAddress(clusterOffset, computationOffset);

// Comp def account
const baseSeed = getArciumAccountBaseSeed('ComputationDefinitionAccount');
const offsetBytes = getCompDefAccOffset('my_computation');
const [compDefAccount] = PublicKey.findProgramAddressSync(
  [baseSeed, programId.toBuffer(), offsetBytes],
  getArciumProgramId()
);

Account Ordering

Standard order for encrypted instructions:

  1. payer (signer, writable)
  2. mxeAccount (not signer, not writable)
  3. mempoolAccount (not signer, writable)
  4. executingPool (not signer, writable)
  5. computationAccount (not signer, writable)
  6. compDefAccount (not signer, not writable)
  7. clusterAccount (not signer, writable)
  8. Game-specific accounts
  9. SystemProgram.programId
  10. arciumProgramId

Common Errors

Error Cause Solution
ARCIUM_CLUSTER_OFFSET is missing Missing env var Add to .env.local
MXE Public Key not found MXE not initialized Initialize MXE account first
Account not found Wrong PDA derivation Check cluster offset matches network

Detailed References

For in-depth explanations, see:

Weekly Installs
3
First Seen
Jan 21, 2026
Installed on
cursor3
trae2
antigravity2
claude-code2
codex2
gemini-cli2