You are an LLM asked to wire encrypted Solana flows using the npm package arcium-frontend-sdk. Follow this checklist and use only the published package (no local ../src imports).
npm install arcium-frontend-sdk @coral-xyz/anchor @solana/web3.js @arcium-hq/clientARCIUM_CLUSTER_OFFSET(number, required).NEXT_PUBLIC_MXE_PROGRAM_ID(program ID to target).NEXT_PUBLIC_RPC_URLorRPC_URL(optional, defaults to devnet).POOL_ACCOUNT_PUBKEY/CLOCK_ACCOUNT_PUBKEY(defaults provided):
POOL_ACCOUNT_PUBKEY=FsWbPQcJQ2cCyr9ndse13fDqds4F2Ezx2WgTL25Dke4M
CLOCK_ACCOUNT_PUBKEY=AxygBawEvVwZPetj3yPJb9sGdZvaJYsVguET1zFUQkV
Before calling encrypted instructions, you must initialize each comp def once. This requires the LUT address (new in v0.7.0):
import { deriveCompDefAccounts } from 'arcium-frontend-sdk';
const { compDefAccount, mxeAccount, addressLookupTable } = await deriveCompDefAccounts(provider, {
programId: program.programId,
compDefName: 'my_computation', // snake_case name matching your circuit
});
await program.methods.initMyComputationCompDef()
.accounts({ compDefAccount, payer: wallet.publicKey, mxeAccount, addressLookupTable })
.signers([wallet])
.rpc({ preflightCommitment: 'confirmed', commitment: 'confirmed' });- Read env:
const env = ensureEnvConfig(); // from arcium-frontend-sdk
const programId = new PublicKey(process.env.NEXT_PUBLIC_MXE_PROGRAM_ID!);- Fetch MXE public key (consumer provides the call):
const mxePublicKey = await getMXEPublicKey(provider, programId); // from @arcium-hq/client- Pick computation offset:
const computationOffset = randomComputationOffset();- Encrypt inputs:
const encrypted = prepareEncryptionPayload({
values: [...], // bigint/number[]
mxePublicKey, // Uint8Array
});- Derive PDAs:
const derived = deriveCoreAccounts({
programId,
clusterOffset: env.clusterOffset,
computationOffset,
compDefOffset: 'your_comp_def', // string or bytes
});- Build instruction data (use your 8-byte discriminator):
const data = encodeEncryptedCall({
discriminator,
computationOffset,
encryptionPubkey: encrypted.encryptionPubkey,
nonce: encrypted.nonce,
ciphertexts: encrypted.ciphertexts,
});- Accounts (IDL order). Include pool/clock (defaults above; override via env):
const accounts = [
{ pubkey: wallet.publicKey, isSigner: true, isWritable: true },
{ pubkey: derived.mxeAccount, isSigner: false, isWritable: false },
{ pubkey: derived.mempoolAccount, isSigner: false, isWritable: true },
{ pubkey: derived.executingPool, isSigner: false, isWritable: true },
{ pubkey: derived.computationAccount, isSigner: false, isWritable: true },
{ pubkey: derived.compDefAccount, isSigner: false, isWritable: false },
{ pubkey: derived.clusterAccount, isSigner: false, isWritable: true },
{ pubkey: new PublicKey(process.env.POOL_ACCOUNT_PUBKEY ?? 'FsWbPQcJQ2cCyr9ndse13fDqds4F2Ezx2WgTL25Dke4M'), isSigner: false, isWritable: true },
{ pubkey: new PublicKey(process.env.CLOCK_ACCOUNT_PUBKEY ?? 'AxygBawEvVwZPetj3yPJb9sGdZvaJYsVguET1zFUQkV'), isSigner: false, isWritable: false },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
{ pubkey: derived.arciumProgramId, isSigner: false, isWritable: false },
];- Build instruction and transaction:
const { ix } = buildInstruction({ programId, accounts, data });
const tx = await buildTransaction(ix, { cuPriceMicro: 1_000, cuLimit: 1_400_000 });
const { blockhash } = await connection.getLatestBlockhash();
tx.recentBlockhash = blockhash;
tx.feePayer = wallet.publicKey;
const signed = await wallet.signTransaction(tx);
const sig = await connection.sendRawTransaction(signed.serialize(), { skipPreflight: true });randomComputationOffset()prepareEncryptionPayload({ values, mxePublicKey })-> nonce, ciphertexts, encryptionPubkey
verifySignedOutputs(outputs)// expectsoutputs.verify_output()assertVerified(outputs)// throws if invalid
deriveCompDefAccounts(provider, { programId, compDefName })— async helper that fetchesmxeAcc.lutOffsetSlotand returns{ compDefAccount, mxeAccount, addressLookupTable, compDefAccAddress, compDefOffset }. Required for allinitCompDefinstructions (v0.7.0+).x25519.utils.randomSecretKey()replacesrandomPrivateKey()(upstream noble/curves rename).@arcium-hq/client@0.8.xnow has"sideEffects": falsefor tree-shaking.
- See
examples/battle-frontend.tsin the package for a runnable sketch combining all steps.