> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Ge0frey/nullgraph/llms.txt
> Use this file to discover all available pages before exploring further.

# PDA Derivation

> Learn how to derive Program Derived Addresses for NullGraph accounts

## Overview

Program Derived Addresses (PDAs) are deterministic addresses derived from seeds and the program ID. NullGraph uses PDAs for all on-chain accounts to ensure predictable, collision-free addressing.

## Seed Constants

All PDA seeds are defined in the constants file:

```typescript lib/constants.ts theme={null}
export const SEEDS = {
  PROTOCOL_STATE: 'protocol_state',
  NULL_RESULT: 'null_result',
  NULL_BOUNTY: 'null_bounty',
  BOUNTY_VAULT: 'bounty_vault',
  BOUNTY_SUBMISSION: 'bounty_submission',
} as const;
```

## PDA Functions

All PDA derivation functions are located in `lib/pda.ts` and follow the same pattern:

```typescript theme={null}
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';
import { PROGRAM_ID, SEEDS } from './constants';
```

***

### findProtocolStatePDA

Derive the global protocol state account address.

```typescript theme={null}
function findProtocolStatePDA(): [PublicKey, number]
```

#### Seed Structure

<ParamField path="seeds[0]" type="Buffer">
  `Buffer.from('protocol_state')`
</ParamField>

#### Usage Example

```typescript theme={null}
import { findProtocolStatePDA } from '@/lib/pda';

const [protocolStatePDA, bump] = findProtocolStatePDA();
console.log('Protocol State:', protocolStatePDA.toString());
console.log('Bump:', bump);
```

#### Implementation

```typescript lib/pda.ts theme={null}
export function findProtocolStatePDA(): [PublicKey, number] {
  return PublicKey.findProgramAddressSync(
    [Buffer.from(SEEDS.PROTOCOL_STATE)],
    PROGRAM_ID
  );
}
```

<Note>
  There is only one protocol state account per program deployment.
</Note>

***

### findNullResultPDA

Derive the address for a specific null result (NKA) submission.

```typescript theme={null}
function findNullResultPDA(
  researcher: PublicKey,
  specimenNumber: number | BN
): [PublicKey, number]
```

#### Parameters

<ParamField path="researcher" type="PublicKey" required>
  The public key of the researcher submitting the null result
</ParamField>

<ParamField path="specimenNumber" type="number | BN" required>
  The specimen number (NKA counter value). Can be a JavaScript number or BN instance.
</ParamField>

#### Seed Structure

<ParamField path="seeds[0]" type="Buffer">
  `Buffer.from('null_result')`
</ParamField>

<ParamField path="seeds[1]" type="Buffer">
  `researcher.toBuffer()` - 32 bytes
</ParamField>

<ParamField path="seeds[2]" type="Buffer">
  `specimenNumber` as little-endian u64 - 8 bytes
</ParamField>

#### Usage Example

```typescript theme={null}
import { findNullResultPDA } from '@/lib/pda';
import { useWallet } from '@solana/wallet-adapter-react';
import { useProtocolState } from '@/hooks/useProtocolState';

function MyComponent() {
  const { publicKey } = useWallet();
  const { data: protocol } = useProtocolState();

  if (!publicKey || !protocol) return null;

  const nextSpecimen = protocol.nkaCounter.toNumber() + 1;
  const [nullResultPDA, bump] = findNullResultPDA(publicKey, nextSpecimen);

  console.log(`Next NKA-${String(nextSpecimen).padStart(4, '0')} PDA:`, nullResultPDA.toString());
}
```

#### Implementation

```typescript lib/pda.ts theme={null}
export function findNullResultPDA(
  researcher: PublicKey,
  specimenNumber: number | BN
): [PublicKey, number] {
  const bn = typeof specimenNumber === 'number' ? new BN(specimenNumber) : specimenNumber;
  return PublicKey.findProgramAddressSync(
    [
      Buffer.from(SEEDS.NULL_RESULT),
      researcher.toBuffer(),
      bn.toArrayLike(Buffer, 'le', 8),
    ],
    PROGRAM_ID
  );
}
```

***

### findBountyPDA

Derive the address for a specific bounty.

```typescript theme={null}
function findBountyPDA(
  creator: PublicKey,
  bountyNumber: number | BN
): [PublicKey, number]
```

#### Parameters

<ParamField path="creator" type="PublicKey" required>
  The public key of the bounty creator
</ParamField>

<ParamField path="bountyNumber" type="number | BN" required>
  The bounty number (bounty counter value)
</ParamField>

#### Seed Structure

<ParamField path="seeds[0]" type="Buffer">
  `Buffer.from('null_bounty')`
</ParamField>

<ParamField path="seeds[1]" type="Buffer">
  `creator.toBuffer()` - 32 bytes
</ParamField>

<ParamField path="seeds[2]" type="Buffer">
  `bountyNumber` as little-endian u64 - 8 bytes
</ParamField>

#### Usage Example

```typescript theme={null}
import { findBountyPDA } from '@/lib/pda';
import { useWallet } from '@solana/wallet-adapter-react';

function MyBounties() {
  const { publicKey } = useWallet();

  if (!publicKey) return null;

  // Derive PDA for my first bounty
  const [bounty1PDA, bump] = findBountyPDA(publicKey, 1);
  console.log('My first bounty:', bounty1PDA.toString());
}
```

#### Implementation

```typescript lib/pda.ts theme={null}
export function findBountyPDA(
  creator: PublicKey,
  bountyNumber: number | BN
): [PublicKey, number] {
  const bn = typeof bountyNumber === 'number' ? new BN(bountyNumber) : bountyNumber;
  return PublicKey.findProgramAddressSync(
    [
      Buffer.from(SEEDS.NULL_BOUNTY),
      creator.toBuffer(),
      bn.toArrayLike(Buffer, 'le', 8),
    ],
    PROGRAM_ID
  );
}
```

***

### findVaultPDA

Derive the token vault address for a specific bounty.

```typescript theme={null}
function findVaultPDA(bountyPDA: PublicKey): [PublicKey, number]
```

#### Parameters

<ParamField path="bountyPDA" type="PublicKey" required>
  The public key of the bounty account
</ParamField>

#### Seed Structure

<ParamField path="seeds[0]" type="Buffer">
  `Buffer.from('bounty_vault')`
</ParamField>

<ParamField path="seeds[1]" type="Buffer">
  `bountyPDA.toBuffer()` - 32 bytes
</ParamField>

#### Usage Example

```typescript theme={null}
import { findBountyPDA, findVaultPDA } from '@/lib/pda';
import { PublicKey } from '@solana/web3.js';

const creator = new PublicKey('...');
const [bountyPDA] = findBountyPDA(creator, 1);
const [vaultPDA, bump] = findVaultPDA(bountyPDA);

console.log('Bounty vault:', vaultPDA.toString());
```

#### Implementation

```typescript lib/pda.ts theme={null}
export function findVaultPDA(bountyPDA: PublicKey): [PublicKey, number] {
  return PublicKey.findProgramAddressSync(
    [Buffer.from(SEEDS.BOUNTY_VAULT), bountyPDA.toBuffer()],
    PROGRAM_ID
  );
}
```

<Note>
  The vault is a token account that holds BIO tokens for the bounty reward. It's owned by the program and uses the bounty PDA as a seed.
</Note>

***

### findSubmissionPDA

Derive the address for a bounty submission.

```typescript theme={null}
function findSubmissionPDA(
  bountyPDA: PublicKey,
  nullResultPDA: PublicKey
): [PublicKey, number]
```

#### Parameters

<ParamField path="bountyPDA" type="PublicKey" required>
  The public key of the bounty
</ParamField>

<ParamField path="nullResultPDA" type="PublicKey" required>
  The public key of the null result being submitted
</ParamField>

#### Seed Structure

<ParamField path="seeds[0]" type="Buffer">
  `Buffer.from('bounty_submission')`
</ParamField>

<ParamField path="seeds[1]" type="Buffer">
  `bountyPDA.toBuffer()` - 32 bytes
</ParamField>

<ParamField path="seeds[2]" type="Buffer">
  `nullResultPDA.toBuffer()` - 32 bytes
</ParamField>

#### Usage Example

```typescript theme={null}
import { findSubmissionPDA, findBountyPDA, findNullResultPDA } from '@/lib/pda';
import { PublicKey } from '@solana/web3.js';

const creator = new PublicKey('...');
const researcher = new PublicKey('...');

const [bountyPDA] = findBountyPDA(creator, 1);
const [nullResultPDA] = findNullResultPDA(researcher, 5);
const [submissionPDA, bump] = findSubmissionPDA(bountyPDA, nullResultPDA);

console.log('Submission PDA:', submissionPDA.toString());
```

#### Implementation

```typescript lib/pda.ts theme={null}
export function findSubmissionPDA(
  bountyPDA: PublicKey,
  nullResultPDA: PublicKey
): [PublicKey, number] {
  return PublicKey.findProgramAddressSync(
    [
      Buffer.from(SEEDS.BOUNTY_SUBMISSION),
      bountyPDA.toBuffer(),
      nullResultPDA.toBuffer(),
    ],
    PROGRAM_ID
  );
}
```

<Warning>
  Each null result can only be submitted to a bounty once. The PDA ensures uniqueness.
</Warning>

***

## PDA Relationships

Here's how PDAs relate to each other:

```mermaid theme={null}
graph TD
    A[Protocol State] -->|nkaCounter| B[Null Result]
    A -->|bountyCounter| C[Bounty]
    C -->|PDA| D[Vault]
    B -->|submit| E[Submission]
    C -->|submit| E
```

## Common Patterns

### Deriving Next Account

```typescript theme={null}
import { useProtocolState } from '@/hooks/useProtocolState';
import { findNullResultPDA } from '@/lib/pda';
import { useWallet } from '@solana/wallet-adapter-react';

function useNextNullResultPDA() {
  const { publicKey } = useWallet();
  const { data: protocol } = useProtocolState();

  if (!publicKey || !protocol) return null;

  const nextSpecimen = protocol.nkaCounter.toNumber() + 1;
  return findNullResultPDA(publicKey, nextSpecimen);
}
```

### Checking Account Existence

```typescript theme={null}
import { useProgram } from '@/context/ProgramContext';
import { findNullResultPDA } from '@/lib/pda';
import { PublicKey } from '@solana/web3.js';

async function checkNullResultExists(
  program: Program,
  researcher: PublicKey,
  specimenNumber: number
): Promise<boolean> {
  try {
    const [pda] = findNullResultPDA(researcher, specimenNumber);
    await program.account.nullResult.fetch(pda);
    return true;
  } catch {
    return false;
  }
}
```

### Batch Deriving PDAs

```typescript theme={null}
import { findNullResultPDA } from '@/lib/pda';
import { PublicKey } from '@solana/web3.js';

function deriveMultipleNullResults(
  researcher: PublicKey,
  startNum: number,
  count: number
): PublicKey[] {
  return Array.from({ length: count }, (_, i) => {
    const [pda] = findNullResultPDA(researcher, startNum + i);
    return pda;
  });
}

// Example: Get PDAs for NKA-0001 through NKA-0010
const researcher = new PublicKey('...');
const pdas = deriveMultipleNullResults(researcher, 1, 10);
```

## Return Values

All PDA functions return a tuple:

<ResponseField name="[0]" type="PublicKey">
  The derived Program Derived Address
</ResponseField>

<ResponseField name="[1]" type="number">
  The bump seed (0-255) used to find the PDA off the ed25519 curve
</ResponseField>

## Best Practices

<Tip>
  Always use the PDA derivation functions instead of hardcoding addresses. PDAs are deterministic and will be the same across all clients.
</Tip>

<Warning>
  When incrementing counters (specimenNumber, bountyNumber), always fetch the latest protocol state first to avoid PDA collisions.
</Warning>

<Note>
  The bump seed is automatically stored in account data by the program. You typically don't need to use it in frontend code.
</Note>

## Next Steps

<CardGroup cols={2}>
  <Card title="Hooks" icon="hook" href="/sdk/hooks">
    Learn how hooks use PDAs internally for transactions
  </Card>

  <Card title="Types" icon="code" href="/sdk/types">
    Explore account structures that live at these PDAs
  </Card>
</CardGroup>
