Skip to main content

Account Structs

When making CPI calls to Inco Lightning, you need to pass specific account structures. This guide explains each account struct and when to use it.

Overview

StructPurposeUsed By
OperationGeneral encrypted operationsAll arithmetic, comparison, bitwise, random, input, select functions
AllowGrant/revoke decryption accessallow function
IsAllowedCheck decryption permissionsis_allowed function
VerifySignatureVerify attestation signaturesis_validsignature function

Operation

The simplest account struct, used for most encrypted operations.
use inco_lightning::cpi::accounts::Operation;

pub struct Operation<'info> {
    pub signer: AccountInfo<'info>,
}
When to use: Any encrypted computation - arithmetic (e_add, e_sub, e_mul, e_rem), comparisons (e_ge, e_gt, e_le, e_lt, e_eq), bitwise operations (e_and, e_or, e_not, e_shl, e_shr), random generation (e_rand), input functions (new_euint128, new_ebool, as_euint128, as_ebool), and conditional selection (e_select).
let cpi_ctx = CpiContext::new(
    ctx.accounts.inco_lightning_program.to_account_info(),
    Operation {
        signer: ctx.accounts.authority.to_account_info(),
    },
);

let result = e_add(cpi_ctx, a, b, 0)?;

Allow

Used to grant or revoke decryption permissions for a handle.
use inco_lightning::cpi::accounts::Allow;

pub struct Allow<'info> {
    pub allowance_account: AccountInfo<'info>,
    pub signer: AccountInfo<'info>,
    pub allowed_address: AccountInfo<'info>,
    pub system_program: AccountInfo<'info>,
}
When to use: When you need to grant an address permission to decrypt a handle, or revoke previously granted permission.
AccountDescription
allowance_accountPDA that stores the allowance state (mutable)
signerThe handle owner who can grant permissions (mutable, signer)
allowed_addressThe address being granted/revoked access
system_programRequired for PDA creation

Allowance PDA Derivation

The allowance account is a PDA derived from the handle and allowed address:
seeds = [handle.to_le_bytes(), allowed_address]
Client-side (TypeScript):
import { PublicKey } from '@solana/web3.js';

const INCO_LIGHTNING_PROGRAM_ID = new PublicKey('5sjEbPiqgZrYwR31ahR6Uk9wf5awoX61YGg7jExQSwaj');

function findAllowanceAccount(handle: bigint, allowedAddress: PublicKey): PublicKey {
  const handleBuffer = Buffer.alloc(16);
  handleBuffer.writeBigUInt64LE(handle & BigInt('0xFFFFFFFFFFFFFFFF'), 0);
  handleBuffer.writeBigUInt64LE(handle >> BigInt(64), 8);

  const [allowanceAccount] = PublicKey.findProgramAddressSync(
    [handleBuffer, allowedAddress.toBuffer()],
    INCO_LIGHTNING_PROGRAM_ID
  );

  return allowanceAccount;
}

Usage

let cpi_ctx = CpiContext::new(
    ctx.accounts.inco_lightning_program.to_account_info(),
    Allow {
        allowance_account: ctx.accounts.allowance_account.to_account_info(),
        signer: ctx.accounts.authority.to_account_info(),
        allowed_address: ctx.accounts.allowed_address.to_account_info(),
        system_program: ctx.accounts.system_program.to_account_info(),
    },
);

// Grant access
allow(cpi_ctx, handle, true, allowed_address)?;

// Or revoke access
allow(cpi_ctx, handle, false, allowed_address)?;

IsAllowed

Used to check if an address has decryption permission.
use inco_lightning::cpi::accounts::IsAllowed;

pub struct IsAllowed<'info> {
    pub allowance_account: AccountInfo<'info>,
    pub allowed_address: AccountInfo<'info>,
}
When to use: When you need to verify if an address can decrypt a handle before performing an action.
let cpi_ctx = CpiContext::new(
    ctx.accounts.inco_lightning_program.to_account_info(),
    IsAllowed {
        allowance_account: ctx.accounts.allowance_account.to_account_info(),
        allowed_address: ctx.accounts.allowed_address.to_account_info(),
    },
);

let has_access = is_allowed(cpi_ctx, handle)?;

VerifySignature

Used to verify Ed25519 signatures from the covalidator network for attested decryption.
use inco_lightning::cpi::accounts::VerifySignature;

pub struct VerifySignature<'info> {
    pub instructions: AccountInfo<'info>,
    pub signer: AccountInfo<'info>,
}
When to use: When verifying that decrypted values came from the covalidator network (attested decryption).
AccountDescription
instructionsThe instructions sysvar (SYSVAR_INSTRUCTIONS_ID)
signerTransaction signer (mutable, signer)
use solana_program::sysvar::instructions::ID as SYSVAR_INSTRUCTIONS_ID;

let cpi_ctx = CpiContext::new(
    ctx.accounts.inco_lightning_program.to_account_info(),
    VerifySignature {
        instructions: ctx.accounts.instructions.to_account_info(),
        signer: ctx.accounts.authority.to_account_info(),
    },
);

let results = is_validsignature(
    cpi_ctx,
    1,                      // expected signature count
    Some(handles),
    Some(plaintext_values),
)?;

Setting Up Your Instruction

Your instruction’s account struct needs to include the Inco Lightning program:
use inco_lightning::ID as INCO_LIGHTNING_ID;

#[derive(Accounts)]
pub struct MyInstruction<'info> {
    #[account(mut)]
    pub authority: Signer<'info>,

    #[account(mut)]
    pub my_account: Account<'info, MyAccount>,

    /// CHECK: Inco Lightning program
    #[account(address = INCO_LIGHTNING_ID)]
    pub inco_lightning_program: AccountInfo<'info>,
}
For access control operations, include additional accounts:
#[derive(Accounts)]
pub struct GrantAccess<'info> {
    #[account(mut)]
    pub authority: Signer<'info>,

    /// CHECK: Allowance PDA
    #[account(mut)]
    pub allowance_account: AccountInfo<'info>,

    /// CHECK: Address being granted access
    pub allowed_address: AccountInfo<'info>,

    /// CHECK: Inco Lightning program
    #[account(address = INCO_LIGHTNING_ID)]
    pub inco_lightning_program: AccountInfo<'info>,

    pub system_program: Program<'info, System>,
}
For signature verification, include the instructions sysvar:
use solana_program::sysvar::instructions::ID as SYSVAR_INSTRUCTIONS_ID;

#[derive(Accounts)]
pub struct VerifyDecryption<'info> {
    #[account(mut)]
    pub authority: Signer<'info>,

    /// CHECK: Instructions sysvar
    #[account(address = SYSVAR_INSTRUCTIONS_ID)]
    pub instructions: AccountInfo<'info>,

    /// CHECK: Inco Lightning program
    #[account(address = INCO_LIGHTNING_ID)]
    pub inco_lightning_program: AccountInfo<'info>,
}