> ## 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.

# TypeScript Types

> Complete reference for NullGraph TypeScript interfaces and type definitions

## Overview

The NullGraph SDK provides fully typed TypeScript interfaces for all on-chain accounts, ensuring type safety when building frontend applications.

## Account Interfaces

All account types are exported from `types/index.ts`:

```typescript theme={null}
import type { PublicKey } from '@solana/web3.js';
import type { BN } from '@coral-xyz/anchor';
```

***

### ProtocolStateAccount

The global protocol state containing counters, fees, and treasury information.

```typescript theme={null}
interface ProtocolStateAccount {
  authority: PublicKey;
  nkaCounter: BN;
  bountyCounter: BN;
  feeBasisPoints: number;
  treasury: PublicKey;
  bump: number;
}
```

#### Fields

<ParamField path="authority" type="PublicKey">
  The protocol authority that can update fees and treasury
</ParamField>

<ParamField path="nkaCounter" type="BN">
  Total number of null results submitted. Next submission will be `nkaCounter + 1`
</ParamField>

<ParamField path="bountyCounter" type="BN">
  Total number of bounties created. Next bounty will be `bountyCounter + 1`
</ParamField>

<ParamField path="feeBasisPoints" type="number">
  Protocol fee in basis points (e.g., 250 = 2.5%). Applied when bounties are fulfilled.
</ParamField>

<ParamField path="treasury" type="PublicKey">
  Treasury address that receives protocol fees
</ParamField>

<ParamField path="bump" type="number">
  PDA bump seed for the protocol state account
</ParamField>

#### Usage Example

```typescript theme={null}
import { useProtocolState } from '@/hooks/useProtocolState';
import type { ProtocolStateAccount } from '@/types';

function ProtocolInfo() {
  const { data } = useProtocolState();

  if (!data) return null;

  const feePercent = data.feeBasisPoints / 100;

  return (
    <div>
      <p>Total NKAs: {data.nkaCounter.toString()}</p>
      <p>Total Bounties: {data.bountyCounter.toString()}</p>
      <p>Protocol Fee: {feePercent}%</p>
      <p>Treasury: {data.treasury.toString()}</p>
    </div>
  );
}
```

***

### NullResultAccount

A null result (NKA) submission containing research metadata and statistical information.

```typescript theme={null}
interface NullResultAccount {
  researcher: PublicKey;
  specimenNumber: BN;
  hypothesis: number[];
  methodology: number[];
  expectedOutcome: number[];
  actualOutcome: number[];
  pValue: number;
  sampleSize: number;
  dataHash: number[];
  status: number;
  createdAt: BN;
  bump: number;
}
```

#### Fields

<ParamField path="researcher" type="PublicKey">
  Public key of the researcher who submitted this null result
</ParamField>

<ParamField path="specimenNumber" type="BN">
  Unique specimen number (e.g., 1 for NKA-0001)
</ParamField>

<ParamField path="hypothesis" type="number[]">
  UTF-8 encoded hypothesis string as byte array (max 256 bytes)
</ParamField>

<ParamField path="methodology" type="number[]">
  UTF-8 encoded methodology description as byte array (max 512 bytes)
</ParamField>

<ParamField path="expectedOutcome" type="number[]">
  UTF-8 encoded expected outcome as byte array (max 256 bytes)
</ParamField>

<ParamField path="actualOutcome" type="number[]">
  UTF-8 encoded actual outcome as byte array (max 256 bytes)
</ParamField>

<ParamField path="pValue" type="number">
  Statistical p-value (0.0 to 1.0) indicating significance
</ParamField>

<ParamField path="sampleSize" type="number">
  Number of samples in the study
</ParamField>

<ParamField path="dataHash" type="number[]">
  32-byte hash of the underlying research data for verification
</ParamField>

<ParamField path="status" type="number">
  Current status: `0` = Pending, `1` = Verified, `2` = Disputed
</ParamField>

<ParamField path="createdAt" type="BN">
  Unix timestamp when the null result was submitted
</ParamField>

<ParamField path="bump" type="number">
  PDA bump seed
</ParamField>

#### Usage Example

```typescript theme={null}
import { useNullResults } from '@/hooks/useNullResults';
import { NKA_STATUS } from '@/types';

function NullResultCard({ result }: { result: NullResultAccount }) {
  const hypothesis = Buffer.from(result.hypothesis).toString('utf-8');
  const methodology = Buffer.from(result.methodology).toString('utf-8');
  const actualOutcome = Buffer.from(result.actualOutcome).toString('utf-8');

  const statusLabel = result.status === NKA_STATUS.PENDING
    ? 'Pending'
    : result.status === NKA_STATUS.VERIFIED
    ? 'Verified'
    : 'Disputed';

  return (
    <div>
      <h3>NKA-{result.specimenNumber.toString().padStart(4, '0')}</h3>
      <p><strong>Status:</strong> {statusLabel}</p>
      <p><strong>Hypothesis:</strong> {hypothesis}</p>
      <p><strong>Methodology:</strong> {methodology}</p>
      <p><strong>Actual Outcome:</strong> {actualOutcome}</p>
      <p><strong>P-Value:</strong> {result.pValue.toFixed(4)}</p>
      <p><strong>Sample Size:</strong> {result.sampleSize}</p>
    </div>
  );
}
```

***

### NullBountyAccount

A bounty offering rewards for matching null results.

```typescript theme={null}
interface NullBountyAccount {
  creator: PublicKey;
  bountyNumber: BN;
  description: number[];
  rewardAmount: BN;
  usdcMint: PublicKey;
  vault: PublicKey;
  deadline: BN;
  status: number;
  matchedSubmission: PublicKey;
  createdAt: BN;
  vaultBump: number;
  bump: number;
}
```

#### Fields

<ParamField path="creator" type="PublicKey">
  Public key of the bounty creator
</ParamField>

<ParamField path="bountyNumber" type="BN">
  Unique bounty number (e.g., 1 for NB-0001)
</ParamField>

<ParamField path="description" type="number[]">
  UTF-8 encoded bounty description as byte array (max 512 bytes)
</ParamField>

<ParamField path="rewardAmount" type="BN">
  Reward amount in token lamports (BIO has 6 decimals)
</ParamField>

<ParamField path="usdcMint" type="PublicKey">
  Mint address of the reward token (typically BIO token)
</ParamField>

<ParamField path="vault" type="PublicKey">
  Token account holding the bounty reward
</ParamField>

<ParamField path="deadline" type="BN">
  Unix timestamp when the bounty expires
</ParamField>

<ParamField path="status" type="number">
  Current status: `0` = Open, `1` = Matched, `2` = Fulfilled, `3` = Closed
</ParamField>

<ParamField path="matchedSubmission" type="PublicKey">
  Public key of the approved submission (if status is Matched or Fulfilled)
</ParamField>

<ParamField path="createdAt" type="BN">
  Unix timestamp when the bounty was created
</ParamField>

<ParamField path="vaultBump" type="number">
  PDA bump seed for the vault account
</ParamField>

<ParamField path="bump" type="number">
  PDA bump seed for the bounty account
</ParamField>

#### Usage Example

```typescript theme={null}
import { useBounties } from '@/hooks/useBounties';
import { BOUNTY_STATUS } from '@/types';

function BountyCard({ bounty }: { bounty: NullBountyAccount }) {
  const description = Buffer.from(bounty.description).toString('utf-8');
  const rewardBIO = bounty.rewardAmount.toNumber() / 1_000_000; // Convert from lamports
  const deadlineDate = new Date(bounty.deadline.toNumber() * 1000);

  const statusLabel = bounty.status === BOUNTY_STATUS.OPEN
    ? 'Open'
    : bounty.status === BOUNTY_STATUS.MATCHED
    ? 'Matched'
    : bounty.status === BOUNTY_STATUS.FULFILLED
    ? 'Fulfilled'
    : 'Closed';

  const isExpired = Date.now() > deadlineDate.getTime();

  return (
    <div>
      <h3>NB-{bounty.bountyNumber.toString().padStart(4, '0')}</h3>
      <p><strong>Status:</strong> {statusLabel}</p>
      <p><strong>Reward:</strong> {rewardBIO} BIO</p>
      <p><strong>Description:</strong> {description}</p>
      <p><strong>Deadline:</strong> {deadlineDate.toLocaleDateString()}</p>
      {isExpired && <p style={{ color: 'red' }}>Expired</p>}
    </div>
  );
}
```

***

### BountySubmissionAccount

A submission linking a null result to a bounty.

```typescript theme={null}
interface BountySubmissionAccount {
  researcher: PublicKey;
  nullResult: PublicKey;
  bounty: PublicKey;
  status: number;
  createdAt: BN;
  bump: number;
}
```

#### Fields

<ParamField path="researcher" type="PublicKey">
  Public key of the researcher who submitted
</ParamField>

<ParamField path="nullResult" type="PublicKey">
  Public key of the null result being submitted
</ParamField>

<ParamField path="bounty" type="PublicKey">
  Public key of the bounty
</ParamField>

<ParamField path="status" type="number">
  Submission status: `0` = Pending, `1` = Approved, `2` = Rejected
</ParamField>

<ParamField path="createdAt" type="BN">
  Unix timestamp when submission was created
</ParamField>

<ParamField path="bump" type="number">
  PDA bump seed
</ParamField>

#### Usage Example

```typescript theme={null}
import { useBountySubmissions } from '@/hooks/useBountySubmissions';
import { SUBMISSION_STATUS } from '@/types';
import type { PublicKey } from '@solana/web3.js';

function SubmissionList({ bountyKey }: { bountyKey: PublicKey }) {
  const { data: submissions } = useBountySubmissions(bountyKey);

  const pending = submissions.filter(s => s.status === SUBMISSION_STATUS.PENDING);
  const approved = submissions.filter(s => s.status === SUBMISSION_STATUS.APPROVED);
  const rejected = submissions.filter(s => s.status === SUBMISSION_STATUS.REJECTED);

  return (
    <div>
      <h4>Pending: {pending.length}</h4>
      <h4>Approved: {approved.length}</h4>
      <h4>Rejected: {rejected.length}</h4>
    </div>
  );
}
```

***

## Extended Types with Public Keys

For convenience, the SDK provides extended interfaces that include the account's public key:

### NullResultWithKey

```typescript theme={null}
interface NullResultWithKey extends NullResultAccount {
  publicKey: PublicKey;
}
```

Returned by `useNullResults()` hook.

### NullBountyWithKey

```typescript theme={null}
interface NullBountyWithKey extends NullBountyAccount {
  publicKey: PublicKey;
}
```

Returned by `useBounties()` hook.

### BountySubmissionWithKey

```typescript theme={null}
interface BountySubmissionWithKey extends BountySubmissionAccount {
  publicKey: PublicKey;
}
```

Returned by `useBountySubmissions()` hook.

***

## Status Enums

### NKA\_STATUS

Status values for null results:

```typescript theme={null}
export const NKA_STATUS = {
  PENDING: 0,
  VERIFIED: 1,
  DISPUTED: 2,
} as const;
```

#### Usage Example

```typescript theme={null}
import { NKA_STATUS } from '@/types';
import type { NullResultAccount } from '@/types';

function getStatusLabel(result: NullResultAccount): string {
  switch (result.status) {
    case NKA_STATUS.PENDING:
      return 'Pending Review';
    case NKA_STATUS.VERIFIED:
      return 'Verified';
    case NKA_STATUS.DISPUTED:
      return 'Under Dispute';
    default:
      return 'Unknown';
  }
}
```

***

### BOUNTY\_STATUS

Status values for bounties:

```typescript theme={null}
export const BOUNTY_STATUS = {
  OPEN: 0,
  MATCHED: 1,
  FULFILLED: 2,
  CLOSED: 3,
} as const;
```

#### Status Flow

1. **OPEN (0)**: Bounty is accepting submissions
2. **MATCHED (1)**: Creator approved a submission but hasn't transferred funds yet
3. **FULFILLED (2)**: Reward has been paid out to researcher
4. **CLOSED (3)**: Bounty was closed by creator without fulfillment

#### Usage Example

```typescript theme={null}
import { BOUNTY_STATUS } from '@/types';
import type { NullBountyAccount } from '@/types';

function canSubmit(bounty: NullBountyAccount): boolean {
  return bounty.status === BOUNTY_STATUS.OPEN;
}

function canClose(bounty: NullBountyAccount): boolean {
  return bounty.status === BOUNTY_STATUS.OPEN;
}
```

***

### SUBMISSION\_STATUS

Status values for bounty submissions:

```typescript theme={null}
export const SUBMISSION_STATUS = {
  PENDING: 0,
  APPROVED: 1,
  REJECTED: 2,
} as const;
```

#### Usage Example

```typescript theme={null}
import { SUBMISSION_STATUS } from '@/types';
import type { BountySubmissionAccount } from '@/types';

function getSubmissionColor(submission: BountySubmissionAccount): string {
  switch (submission.status) {
    case SUBMISSION_STATUS.PENDING:
      return 'yellow';
    case SUBMISSION_STATUS.APPROVED:
      return 'green';
    case SUBMISSION_STATUS.REJECTED:
      return 'red';
    default:
      return 'gray';
  }
}
```

***

## Type Guards

Create type guards for runtime type checking:

```typescript theme={null}
import type { NullResultWithKey, NullBountyWithKey } from '@/types';

function isNullResult(account: unknown): account is NullResultWithKey {
  return (
    typeof account === 'object' &&
    account !== null &&
    'specimenNumber' in account &&
    'researcher' in account &&
    'pValue' in account
  );
}

function isNullBounty(account: unknown): account is NullBountyWithKey {
  return (
    typeof account === 'object' &&
    account !== null &&
    'bountyNumber' in account &&
    'creator' in account &&
    'rewardAmount' in account
  );
}
```

***

## Utility Functions

### Converting Byte Arrays to Strings

```typescript theme={null}
function bytesToString(bytes: number[]): string {
  // Remove trailing zeros
  const trimmed = bytes.filter(b => b !== 0);
  return Buffer.from(trimmed).toString('utf-8');
}

// Usage
const hypothesis = bytesToString(nullResult.hypothesis);
```

### Converting Strings to Byte Arrays

```typescript theme={null}
function stringToBytes(str: string, maxLength: number): number[] {
  const buffer = Buffer.from(str, 'utf-8');
  if (buffer.length > maxLength) {
    throw new Error(`String exceeds max length of ${maxLength} bytes`);
  }
  return buffer.toJSON().data;
}

// Usage
const hypothesis = stringToBytes('My hypothesis', 256);
```

### Formatting Timestamps

```typescript theme={null}
import type { BN } from '@coral-xyz/anchor';

function formatTimestamp(timestamp: BN): string {
  const date = new Date(timestamp.toNumber() * 1000);
  return date.toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  });
}

// Usage
const createdDate = formatTimestamp(nullResult.createdAt);
```

### Formatting Token Amounts

```typescript theme={null}
function formatBIO(lamports: BN): string {
  const bio = lamports.toNumber() / 1_000_000;
  return `${bio.toFixed(2)} BIO`;
}

// Usage
const reward = formatBIO(bounty.rewardAmount);
```

***

## Type Safety Best Practices

<Tip>
  Always use the typed interfaces when working with account data. This prevents runtime errors from typos or incorrect field access.
</Tip>

<Warning>
  When converting byte arrays to strings, always check for trailing zeros and handle empty arrays gracefully.
</Warning>

<Note>
  Use `BN.toNumber()` carefully with large numbers. For display purposes, consider using `BN.toString()` instead to avoid precision loss.
</Note>

***

## Complete Type Import

Import all types in one statement:

```typescript theme={null}
import type {
  ProtocolStateAccount,
  NullResultAccount,
  NullBountyAccount,
  BountySubmissionAccount,
  NullResultWithKey,
  NullBountyWithKey,
  BountySubmissionWithKey,
} from '@/types';

import {
  NKA_STATUS,
  BOUNTY_STATUS,
  SUBMISSION_STATUS,
} from '@/types';
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Hooks" icon="hook" href="/sdk/hooks">
    Learn how to fetch and manipulate these types with React hooks
  </Card>

  <Card title="PDA Derivation" icon="key" href="/sdk/pda-derivation">
    Understand how to derive addresses for these accounts
  </Card>
</CardGroup>
