Skip to main content
The NullGraph program uses four primary account types to manage protocol state, null results, bounties, and submissions. All accounts are Program Derived Addresses (PDAs) owned by the program.

ProtocolState

Global singleton storing protocol configuration and auto-incrementing counters. Location: lib.rs:472-481 PDA Seeds: ["protocol_state"] Space: 8 + ProtocolState::INIT_SPACE (8-byte discriminator + 83 bytes)

Fields

Pubkey
required
Protocol admin wallet with permission to modify global settings. Set during initialize_protocol.
u64
required
Auto-incrementing counter for NKA specimen numbers. Starts at 0, incremented by submit_null_result. Used to derive sequential IDs (NKA-0001, NKA-0002, …).
u64
required
Auto-incrementing counter for bounty numbers. Starts at 0, incremented by create_bounty. Used to derive sequential IDs (NB-0001, NB-0002, …).
u16
required
Protocol fee rate in basis points (1/100th of a percent). Default: 250 (2.5%). Used in approve_bounty_submission to calculate treasury fee.Example: 250 = 2.5%, 100 = 1%, 1000 = 10%
Pubkey
required
Treasury wallet address receiving protocol fees. Validated by admin during initialization. Must have an associated USDC token account.
u8
required
PDA bump seed for the ProtocolState account. Stored to avoid recomputation in subsequent instructions.

Code Reference


NullResult

Stores complete scientific metadata for a single Null Knowledge Asset (NKA). Location: lib.rs:483-498 PDA Seeds: ["null_result", researcher.key().as_ref(), &(nka_counter + 1).to_le_bytes()] Space: 8 + NullResult::INIT_SPACE (8-byte discriminator + 601 bytes)

Fields

Pubkey
required
Wallet address of the researcher who submitted this NKA. Used for has_one constraint in submit_to_bounty.
u64
required
Sequential identifier assigned from protocol_state.nka_counter. Displayed as NKA-{specimen_number:04} in the frontend.
[u8; 128]
required
UTF-8 encoded hypothesis tested in the experiment. Fixed-size buffer, zero-padded. Maximum 128 bytes.Example: “Increasing dopamine levels improves working memory in rats”
[u8; 128]
required
UTF-8 encoded summary of experimental methodology. Fixed-size buffer, zero-padded. Maximum 128 bytes.Example: “Double-blind RCT with 50 subjects, t-test analysis”
[u8; 128]
required
UTF-8 encoded description of what was expected. Fixed-size buffer, zero-padded. Maximum 128 bytes.Example: “Significant improvement in test scores (p < 0.05)”
[u8; 128]
required
UTF-8 encoded description of what actually occurred. Fixed-size buffer, zero-padded. Maximum 128 bytes.Example: “No significant difference observed (p = 0.42)”
u32
required
Statistical p-value stored as fixed-point integer (multiply by 10000). To convert: p_value / 10000.0.Example: 4200 = 0.42, 500 = 0.05, 8700 = 0.87
u32
required
Number of subjects/observations in the experiment. Stored as raw integer.Example: 50, 1000, 250
[u8; 32]
required
SHA-256 hash of the underlying dataset file. Provides tamper-proof link between on-chain record and off-chain data. Can be all zeros if no file attached.Computation: SHA256(raw_data_file_bytes)
u8
required
Verification status of the null result:
  • 0 = Pending (default)
  • 1 = Verified (community validated)
  • 2 = Disputed (challenged by peers)
Currently set to 0 on creation. Future versions may implement community verification.
i64
required
Unix timestamp of submission. Set via Clock::get()?.unix_timestamp in submit_null_result:62.
u8
required
PDA bump seed for this NullResult account.

Code Reference


NullBounty

Bounty posted by a creator seeking a specific null result. Escrows USDC in a PDA-controlled vault. Location: lib.rs:500-515 PDA Seeds: ["null_bounty", creator.key().as_ref(), &(bounty_counter + 1).to_le_bytes()] Vault Seeds: ["bounty_vault", bounty.key().as_ref()] Space: 8 + NullBounty::INIT_SPACE (8-byte discriminator + 419 bytes)

Fields

Pubkey
required
Wallet address of the bounty creator. Used for has_one constraint in approve_bounty_submission and close_bounty.
u64
required
Sequential identifier assigned from protocol_state.bounty_counter. Displayed as NB-{bounty_number:04} in the frontend.
[u8; 256]
required
UTF-8 encoded description of the desired null result. Fixed-size buffer, zero-padded. Maximum 256 bytes.Example: “Negative result for CRISPR-based treatment of Huntington’s disease in mouse models”
u64
required
USDC reward in base units (6 decimals). Must be > 0 (validated in create_bounty:78). Escrowed in vault on creation.Example: 1000000 = 1 USDC, 2500000 = 2.5 USDC
Pubkey
required
USDC token mint address. Stored to validate transfers in approve_bounty_submission and close_bounty.
Pubkey
required
Address of the PDA token account holding escrowed USDC. Authority is the vault itself.
i64
required
Unix timestamp deadline for bounty submissions. Currently not enforced by program but used for frontend filtering.
u8
required
Bounty lifecycle status:
  • 0 = Open (accepting submissions)
  • 1 = Matched (submission linked, pending approval)
  • 2 = Fulfilled (submission approved, payout complete)
  • 3 = Closed (refunded, no longer active)
Pubkey
required
Address of the BountySubmission PDA if status is Matched/Fulfilled. Set to Pubkey::default() (all zeros) when Open or Closed.
i64
required
Unix timestamp of bounty creation. Set via Clock::get()?.unix_timestamp in create_bounty:94.
u8
required
PDA bump seed for the vault token account. Used to derive signer seeds for CPI transfers.
u8
required
PDA bump seed for this NullBounty account.

Code Reference


BountySubmission

Junction account linking a researcher’s NullResult to a specific NullBounty. Location: lib.rs:517-526 PDA Seeds: ["bounty_submission", bounty.key().as_ref(), null_result.key().as_ref()] Space: 8 + BountySubmission::INIT_SPACE (8-byte discriminator + 106 bytes)

Fields

Pubkey
required
Wallet address of the researcher submitting their NKA. Copied from the linked NullResult account.
Pubkey
required
Address of the NullResult PDA being submitted. Must be owned by the submitting researcher.
Pubkey
required
Address of the NullBounty PDA this submission is for. Must have status Open when created.
u8
required
Submission approval status:
  • 0 = Pending (awaiting creator review)
  • 1 = Approved (accepted, payout executed)
  • 2 = Rejected (declined by creator - not currently used)
i64
required
Unix timestamp of submission. Set via Clock::get()?.unix_timestamp in submit_to_bounty:131.
u8
required
PDA bump seed for this BountySubmission account.

Code Reference


Account Size Summary

All accounts use Anchor’s #[derive(InitSpace)] macro to automatically calculate the correct space allocation.