The Solana blockchain operates as a transparent public ledger where every transaction is visible to all. While this transparency fosters trust, it presents significant challenges for applications requiring privacy in their computations.
The Arcium Frontend SDK bridges this gap. It provides the necessary client-side logic to interface with the Multi-Party Execution Environment (MXE). By employing this SDK, developers can encrypt data client-side before submission, ensuring that sensitive inputs remain confidential throughout the entire computational lifecycle.
A confidential transaction in the Arcium network flows through three distinct layers, each serving a critical role in the preservation of data privacy.
Data originates here. The SDK employs RescueCipher and X25519 protocols to encrypt raw values into ciphertexts before they depart the browser.
The Solana blockchain serves as the transport layer. It propagates the encrypted payload without exposing the underlying data to observers.
The encrypted payload reaches the Arcium Cluster. Nodes collaboratively decrypt and compute using MPC, revealing only the final result.
To commence integration, install the SDK alongside its peer dependencies. The package requires Node.js version 20.18 or higher.
npm install arcium-frontend-sdk \
@coral-xyz/anchor \
@solana/web3.js \
@arcium-hq/client
For applications utilizing React, install the additional peer dependencies to access the hooks module:
npm install @solana/wallet-adapter-react react
arcium-frontend-sdk/react
To anchor computation to the Solana blockchain, the SDK derives specific Program Derived Addresses (PDAs). Understanding these accounts is crucial for debugging and successful integration.
| Account | Purpose |
|---|---|
| MXE Account | Represents the Cluster Identity. Stores the public encryption key used by clients to encrypt their inputs. |
| Comp. Definition | Contains the WASM bytecode defining the computation logic to be executed by the MXE cluster. |
| Computation | A unique address holding the state of a specific computational request instance. |
| Cluster | Identifies the specific Arcium cluster handling the computation. |
| Mempool | Queue for pending computations awaiting execution. |
| Executing Pool | Tracks computations currently being processed by the cluster. |
import { deriveCoreAccounts } from 'arcium-frontend-sdk';
const accounts = deriveCoreAccounts({
programId,
clusterOffset: 768109697,
computationOffset,
compDefOffset: 'my_computation',
});
// accounts.mxeAccount
// accounts.compDefAccount
// accounts.computationAccount
// accounts.clusterAccount
// accounts.mempoolAccount
// accounts.executingPool
Encryption forms the cornerstone of the SDK. All sensitive values must be encrypted client-side before transmission to the blockchain. The SDK employs X25519 key exchange and RescueCipher for this purpose.
Before encryption, obtain the MXE public key from the chain. The SDK provides retry logic to handle network instability:
import { getMXEPublicKeyWithRetry } from 'arcium-frontend-sdk';
const mxePublicKey = await getMXEPublicKeyWithRetry(
provider,
programId,
{
maxRetries: 10,
retryDelayMs: 500,
onRetry: (attempt, err) => {
console.log(`Attempt ${attempt} failed: ${err.message}`);
},
}
);
With the MXE key in hand, encrypt your sensitive values using prepareEncryptionPayload:
import {
prepareEncryptionPayload,
randomComputationOffset
} from 'arcium-frontend-sdk';
// Generate unique computation offset
const computationOffset = randomComputationOffset();
// Encrypt values (numbers or bigints)
const encrypted = prepareEncryptionPayload({
values: [100n, 50n, 25n],
mxePublicKey,
});
// encrypted.ciphertexts - Encrypted values
// encrypted.encryptionPubkey - Your ephemeral public key
// encrypted.nonce - Encryption nonce
// encrypted.nonceBytes - Raw nonce bytes
Beyond PDA derivation, the SDK provides utilities for managing computation definition accounts and checking their initialization status.
import { getCompDefAccountInfo } from 'arcium-frontend-sdk';
const info = await getCompDefAccountInfo(
provider,
programId,
'my_computation'
);
if (!info.exists) {
console.log('CompDef not initialized');
console.log('Address:', info.address.toBase58());
}
If the computation definition does not exist, initialize it:
import { initCompDefIfNeeded } from 'arcium-frontend-sdk';
const result = await initCompDefIfNeeded({
program, // Anchor Program instance
provider, // Anchor Provider
compDefName: 'my_computation',
// methodName: 'initMyComputationCompDef' // optional
});
if (!result.exists) {
console.log('Initialized:', result.tx);
}
import { getSignerPDA } from 'arcium-frontend-sdk';
const signerPDA = getSignerPDA(programId);
// Used for program-signed operations
The SDK offers two approaches to building transactions: a high-level builder that handles all complexity, and low-level primitives for custom implementations.
The simplest method - handles MXE key fetching, encryption, PDA derivation, and transaction submission:
import { executeEncryptedCall } from 'arcium-frontend-sdk';
const result = await executeEncryptedCall({
provider,
programId,
compDefOffset: 'my_computation',
discriminator: Buffer.from([1,2,3,4,5,6,7,8]),
values: [42n, 100n],
computeBudget: {
cuPriceMicro: 1000,
cuLimit: 1_400_000,
},
});
console.log('Signature:', result.signature);
console.log('Offset:', result.computationOffset.toString());
For fine-grained control, build instructions manually:
import {
encodeEncryptedCall,
buildInstruction,
buildTransaction,
} from 'arcium-frontend-sdk';
// Encode instruction data
const data = encodeEncryptedCall({
discriminator,
computationOffset,
encryptionPubkey: encrypted.encryptionPubkey,
nonce: encrypted.nonce,
ciphertexts: encrypted.ciphertexts,
});
// Build instruction
const { ix } = buildInstruction({
programId,
accounts: accountMetas,
data,
});
// Build transaction with compute budget
const tx = await buildTransaction(ix, {
cuPriceMicro: 1000,
cuLimit: 1_400_000,
});
For React applications, the SDK provides hooks that integrate seamlessly
with @solana/wallet-adapter-react. Import from the /react subpath.
import { useArciumProvider } from 'arcium-frontend-sdk/react';
function MyComponent() {
const { provider, isReady, publicKey } = useArciumProvider();
if (!isReady) {
return <ConnectWalletButton />;
}
// provider is an AnchorProvider
}
import { useEncryption } from 'arcium-frontend-sdk/react';
function EncryptForm({ programId }) {
const { encrypt, generateOffset, isReady, error } = useEncryption(programId);
const handleSubmit = () => {
if (!isReady) return;
const offset = generateOffset();
const encrypted = encrypt([42n, 100n]);
// Use encrypted data...
};
}
import { useMXEPublicKey } from 'arcium-frontend-sdk/react';
function Component({ programId }) {
const { mxePublicKey, isLoading, error, refetch } = useMXEPublicKey(programId);
if (isLoading) return <Spinner />;
if (error) return <Error message={error.message} />;
// mxePublicKey is cached and ready
}
import { useNetwork } from 'arcium-frontend-sdk/react';
function NetworkInfo() {
const { network, clusterAccount, endpoint } = useNetwork();
return (
<div>
Network: {network}
Cluster: {clusterAccount?.toBase58()}
</div>
);
}
import { useComputationResult } from 'arcium-frontend-sdk/react';
function ResultDisplay({ computationOffset, clusterOffset }) {
const { result, isPolling, error, startPolling } = useComputationResult(
computationOffset,
clusterOffset,
true // autoStart
);
if (isPolling) return <Spinner />;
if (result) return <ResultView data={result} />;
}
The SDK provides typed error classes for precise error handling. Each error includes a code, message, and optional cause for detailed debugging.
| Error Class | Description |
|---|---|
ArciumSDKError |
Base class for all SDK errors |
MXEKeyFetchError |
Failed to fetch MXE public key after retries |
EncryptionError |
Encryption operation failed |
TransactionBuildError |
Failed to build or send transaction |
ComputationTimeoutError |
Result polling timed out |
ValidationError |
Input validation failed |
import {
isArciumError,
MXEKeyFetchError,
ComputationTimeoutError,
} from 'arcium-frontend-sdk';
try {
await executeEncryptedCall(config);
} catch (error) {
if (error instanceof MXEKeyFetchError) {
console.log('Fetch failed after', error.attempts, 'attempts');
console.log('Program:', error.programId);
} else if (error instanceof ComputationTimeoutError) {
console.log('Timed out:', error.timeoutMs, 'ms');
console.log('Offset:', error.computationOffset);
} else if (isArciumError(error)) {
console.log('Code:', error.code);
console.log('Details:', error.toDetailedString());
}
}
Configure the SDK through environment variables and runtime settings. The SDK automatically detects network type from the RPC endpoint.
# Required: Cluster offset for PDA derivation
ARCIUM_CLUSTER_OFFSET=768109697
# Optional: RPC endpoint (defaults to devnet)
NEXT_PUBLIC_RPC_URL=https://api.devnet.solana.com
# Your program ID
NEXT_PUBLIC_MXE_PROGRAM_ID=YourProgramId
import {
detectNetwork,
getClusterAccountForNetwork
} from 'arcium-frontend-sdk';
// Detect from endpoint
const network = detectNetwork('https://api.devnet.solana.com');
// Returns: 'devnet' | 'testnet' | 'mainnet-beta' | 'localnet'
// Get cluster account
const clusterAccount = getClusterAccountForNetwork(provider);
Enable debug logging to trace SDK operations:
import { configureSDK } from 'arcium-frontend-sdk';
configureSDK({
debug: true,
logger: (message, data) => {
console.log(`[Arcium] ${message}`, data);
},
});
import {
pollComputationResult,
subscribeToComputationResult
} from 'arcium-frontend-sdk';
// One-time poll
const result = await pollComputationResult(
provider,
computationOffset,
clusterOffset,
{ maxAttempts: 30, intervalMs: 2000 }
);
// Or subscribe
const sub = subscribeToComputationResult(provider, {
computationOffset,
clusterOffset,
onResult: (data) => console.log('Result:', data),
onError: (err) => console.error(err),
});
// Later: sub.unsubscribe();
The SDK includes a comprehensive LLM Integration Guide
(LLM_GUIDE.md) designed specifically for developers using Large Language Models as
programming assistants. This document serves as a structured knowledge base that LLMs can reference
when helping you integrate encrypted Solana computations into your applications.
The LLM_GUIDE.md is a detailed technical reference document located in the SDK's root
directory. It contains structured documentation covering all aspects of the Arcium Frontend SDK,
from installation and configuration to advanced usage patterns and troubleshooting.
Modern LLM assistants excel at understanding context from documentation. By providing access to
LLM_GUIDE.md, you enable them to:
Simply include the LLM_GUIDE.md file in your conversation with an LLM assistant:
LLM_GUIDE.md at the
beginning of your conversation to give the LLM full context about the SDK.
The guide covers all aspects of the SDK in a format optimized for LLM consumption:
• Installation and setup
• Environment configuration
• Core concepts (PDAs, encryption flow)
• High-level and low-level APIs
• Step-by-step transaction building
• Encryption details and algorithms
• Account management
• React integration hooks
• Error handling patterns
• Validation utilities
• Complete working examples
• API reference tables
• Troubleshooting guide
The guide is written with LLM consumption in mind: it uses clear structure, includes type definitions, provides both high-level and low-level approaches, and contains practical examples that can be directly adapted to your use case.