> ## Documentation Index
> Fetch the complete documentation index at: https://luminouslabs-cc5545c6-swen-token-interface.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Retrieve a single ZK Proof used by the compression program to verify that the given accounts are valid and the new addresses can be created. RPC method guide with use cases, tips and examples.

# Getvalidityproof

The`getValidityProof` RPC method generates zero-knowledge proofs to verify that the given accounts are valid or the new addresses can be created. This proof is required for any operation on compressed accounts (transfer, approve, decompress, etc.) for on-chain verification of compressed state.

<Info>
  You can test this method via the OpenAPI example or custom examples below.
</Info>

<Info>
  * Proof limits per request are:
    * `hashes`: 1, 2, 3, 4, or 8
    * `newAddressesWithTrees` : 1, 2
  * The `newAddresses` param field is supported but deprecated. Please use `newAddressesWithTrees`instead.
</Info>

**Common Use Cases**

* **Token Transfers:** Generate proofs required for transferring compressed tokens.
* **Account Operations:** Create proofs needed for any compressed account modification.
* **Batch Processing:** Generate proofs for multiple accounts in a single call.
* **State Tree Verification:** Prove account inclusion in the current state tree.
* **Transaction Building:** Obtain proof data needed for compressed transaction instructions.
* **Program Integration:** Get validity proofs for custom program operations on compressed accounts.

**Parameters**

1. `hashes` (BN254\[], required): Array of BN254 objects representing compressed account hashes to generate proofs for.
2. `newAddresses` (BN254\[], optional): Array of BN254 objects representing new addresses to include in the proof for address tree verification.

**Response**

The response contains ValidityProofWithContext data:

* `compressedProof` (ValidityProof | null): The compressed validity proof object for zero-knowledge verification
* `roots` (BN\[]): Array of merkle tree roots used in proof generation
* `rootIndices` (number\[]): Array of indices of the roots in the state tree
* `leafIndices` (number\[]): Array of indices of the leaves being proven
* `leaves` (BN\[]): Array of leaf values in the merkle tree
* `treeInfos` (TreeInfo\[]): Array of information about the state trees used
* `proveByIndices` (boolean\[]): Array indicating whether to prove by indices for each element

**Developer Tips**

* **Fetch Accounts First**: Always get compressed accounts before generating proofs - you need existing account hashes
* **Batch Processing**: You can generate proofs for multiple accounts in a single call. Allowed counts: 1, 2, 3, 4, or 8 accounts
* **Proof Usage**: The proof is required for any operation that modifies compressed accounts (transfers, burns, etc.)
* **Caching**: Validity proofs are only valid for the current state - don't cache them for long periods
* **Error Handling**: If accounts don't exist or have been modified, proof generation will fail
* **Integration**: Use `proof.compressedProof` and `proof.rootIndices` when building transactions
* **State Changes**: After any transaction, previously generated proofs become invalid for those accounts

**Examples**

The below examples work - just make sure you installed the dependencies.

<Accordion title="Dependencies & Setup">
  ```bash theme={null}
  npm install @lightprotocol/stateless.js @solana/web3.js
  ```
</Accordion>

**Example: Generate Validity Proof**

Generate a validity proof for compressed accounts.

<Tabs>
  <Tab title="TypeScript">
    ```typescript expandable theme={null}
    import { Rpc, createRpc, bn } from '@lightprotocol/stateless.js';
    import { PublicKey } from '@solana/web3.js';

    async function generateValidityProof(): Promise<void> {
      const connection: Rpc = createRpc(
        'https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY',
        'https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY'
      );

      try {
        // Get compressed accounts
        const owner = new PublicKey('OWNER_PUBLIC_KEY_HERE');
        const accounts = await connection.getCompressedAccountsByOwner(owner);

        if (accounts.items.length === 0) {
          console.log('No compressed accounts found');
          return;
        }

        // Generate validity proof
        const hashes = accounts.items.slice(0, 2).map(acc => bn(acc.hash));
        const validityProof = await connection.getValidityProof(hashes);

        console.log('Validity Proof Generated:');
        console.log(\`  Accounts: ${hashes.length}\`);
        console.log(\`  Roots: ${validityProof.roots.length}\`);
        console.log(\`  Root Indices: ${validityProof.rootIndices.length} elements\`);
        console.log(\`  Leaf Indices: ${validityProof.leafIndices.length} elements\`);

        // Ready for use in transactions
        console.log('\nProof ready for compressed transactions');

      } catch (error: unknown) {
        console.error('Error generating validity proof:', error);
      }
    }

    generateValidityProof();
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # Use account hashes from getCompressedAccountsByOwner
    curl -X POST https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY \
      -H "Content-Type: application/json" \
      -d '{
        "jsonrpc": "2.0",
        "id": 1,
        "method": "getValidityProof",
        "params": {
          "hashes": [
            "ACCOUNT_HASH_1",
            "ACCOUNT_HASH_2"
          ]
        }
      }'
    ```
  </Tab>

  <Tab title="Rust">
    <Info>
      **Rust Client**: `light-client` v0.14.0 is available on crates.io. Use `LightClient` for the current stable API.
    </Info>

    ```rust expandable theme={null}
    use light_client::rpc::LightClient;
    use solana_sdk::pubkey::Pubkey;
    use std::str::FromStr;
    use anyhow::Result;

    #[tokio::main]
    async fn main() -> Result<()> {
        let client = LightClient::new("https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY".to_string()).await?;

        // Get compressed accounts first
        let owner = "OWNER_PUBLIC_KEY_HERE";
        let accounts = client.get_compressed_accounts_by_owner(owner).await?;

        if accounts.items.is_empty() {
            println!("No compressed accounts found");
            return Ok(());
        }

        // Generate validity proof for the accounts
        let hashes: Vec<String> = accounts.items.iter()
            .take(2)
            .map(|acc| acc.hash.clone())
            .collect();

        let validity_proof = client.get_validity_proof(hashes.clone()).await?;

        println!("Validity Proof Generated:");
        println!("  Accounts: {}", hashes.len());
        println!("  Roots: {}", validity_proof.roots.len());
        println!("  Root Indices: {}", validity_proof.root_indices.len());

        Ok(())
    }
    ```
  </Tab>
</Tabs>

**Example: Proof Generation for Token Transfer**

Generate a validity proof for a compressed token transfer operation:

```Javascript JavaScript expandable theme={null}
import { Rpc, createRpc, bn } from '@lightprotocol/stateless.js';
import { PublicKey } from '@solana/web3.js';

async function generateProofForTransfer() {
  const connection = createRpc(
    'https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY',
    'https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY'
  );

  try {
    // Get compressed token accounts
    const owner = new PublicKey('OWNER_PUBLIC_KEY_HERE');
    const mint = new PublicKey('TOKEN_MINT_HERE');

    const tokenAccounts = await connection.getCompressedTokenAccountsByOwner(
      owner,
      { mint }
    );

    if (tokenAccounts.items.length === 0) {
      console.log('No compressed token accounts found');
      return;
    }

    // Generate proof for the token accounts (limit to allowed numbers: 1, 2, 3, 4, or 8)
    const limitedAccounts = tokenAccounts.items.slice(0, 4);
    const hashes = limitedAccounts.map(acc => bn(acc.compressedAccount.hash));
    const validityProof = await connection.getValidityProof(hashes);

    console.log('Validity Proof for Transfer:');
    console.log(\`  Token accounts: ${hashes.length}\`);
    console.log(\`  Roots: ${validityProof.roots.length}\`);

    // This proof is now ready to use with LightTokenProgram.transfer()
    console.log('\nProof ready for token transfer instruction');
    console.log('Use this with:');
    console.log('  recentValidityProof: validityProof.compressedProof');
    console.log('  recentInputStateRootIndices: validityProof.rootIndices');

  } catch (error) {
    console.error('Error generating proof:', error);
  }
}

generateProofForTransfer();
```


## OpenAPI

````yaml post /
openapi: 3.0.3
info:
  title: photon-indexer
  description: Solana indexer for general compression
  license:
    name: Apache-2.0
  version: 0.50.0
servers:
  - url: https://mainnet.helius-rpc.com
security: []
paths:
  /:
    summary: getCompressedAccountBalance
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - jsonrpc
                - id
                - method
                - params
              properties:
                id:
                  type: string
                  description: An ID to identify the request.
                  enum:
                    - test-account
                jsonrpc:
                  type: string
                  description: The version of the JSON-RPC protocol.
                  enum:
                    - '2.0'
                method:
                  type: string
                  description: The name of the method to invoke.
                  enum:
                    - getCompressedAccountBalance
                params:
                  type: object
                  description: Request for compressed account data
                  default:
                    address: null
                    hash: '11111111111111111111111111111111'
                  properties:
                    address:
                      allOf:
                        - $ref: '#/components/schemas/SerializablePubkey'
                      nullable: true
                    hash:
                      allOf:
                        - $ref: '#/components/schemas/Hash'
                      nullable: true
                  additionalProperties: false
                  example:
                    address: null
                    hash: '11111111111111111111111111111111'
        required: true
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                type: object
                required:
                  - context
                  - value
                properties:
                  context:
                    $ref: '#/components/schemas/Context'
                  value:
                    $ref: '#/components/schemas/UnsignedInteger'
                additionalProperties: false
        '429':
          description: Exceeded rate limit.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
        '500':
          description: >-
            The server encountered an unexpected condition that prevented it
            from fulfilling the request.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
components:
  schemas:
    SerializablePubkey:
      type: string
      description: A Solana public key represented as a base58 string.
      default: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP
      example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP
    Hash:
      type: string
      description: A 32-byte hash represented as a base58 string.
      example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP
    Context:
      type: object
      required:
        - slot
      properties:
        slot:
          type: integer
          default: 100
          example: 100
    UnsignedInteger:
      type: integer
      default: 100
      example: 100

````