Skip to main content
The NullGraph program emits 6 events to enable off-chain indexing, UI updates, and monitoring. All events are defined using Anchor’s #[event] macro.

Event Structure

Events are emitted using Anchor’s emit! macro and written to transaction logs. They can be parsed by indexers like Helius, QuickNode, or custom RPC listeners. Location: lib.rs:532-573

ProtocolInitialized

Emitted once when the protocol is first initialized. Location: lib.rs:532-536 Emitted by: initialize_protocol (line 30)

Fields

authority
Pubkey
required
The protocol admin wallet address that initialized the protocol.
fee_basis_points
u16
required
The protocol fee rate in basis points (e.g., 250 = 2.5%).

Code Reference

#[event]
pub struct ProtocolInitialized {
    pub authority: Pubkey,
    pub fee_basis_points: u16,
}

Example Usage

Indexers can track protocol deployment and fee configuration:
program.addEventListener('ProtocolInitialized', (event) => {
  console.log('Protocol initialized by:', event.authority.toString());
  console.log('Fee rate:', event.feeBasisPoints / 100, '%');
});

NullResultSubmitted

Emitted when a new Null Knowledge Asset (NKA) is submitted. Location: lib.rs:538-542 Emitted by: submit_null_result (line 65)

Fields

specimen_number
u64
required
The sequential ID assigned to this NKA (e.g., 1, 2, 3…). Displayed as NKA-{specimen_number:04} in the UI.
researcher
Pubkey
required
The wallet address of the researcher who submitted the NKA.

Code Reference

#[event]
pub struct NullResultSubmitted {
    pub specimen_number: u64,
    pub researcher: Pubkey,
}

Example Usage

Track new NKA submissions in real-time:
program.addEventListener('NullResultSubmitted', (event) => {
  console.log(`NKA-${event.specimenNumber.toString().padStart(4, '0')} submitted`);
  console.log('Researcher:', event.researcher.toString());
});

BountyCreated

Emitted when a new bounty is created and USDC is escrowed. Location: lib.rs:544-550 Emitted by: create_bounty (line 114)

Fields

bounty_number
u64
required
The sequential ID assigned to this bounty (e.g., 1, 2, 3…). Displayed as NB-{bounty_number:04} in the UI.
creator
Pubkey
required
The wallet address of the bounty creator.
reward_amount
u64
required
The USDC reward amount in base units (6 decimals). Divide by 1,000,000 to get human-readable USDC.Example: 2500000 = 2.5 USDC
deadline
i64
required
Unix timestamp deadline for submissions.

Code Reference

#[event]
pub struct BountyCreated {
    pub bounty_number: u64,
    pub creator: Pubkey,
    pub reward_amount: u64,
    pub deadline: i64,
}

Example Usage

Monitor new bounties and their rewards:
program.addEventListener('BountyCreated', (event) => {
  const usdcAmount = event.rewardAmount.toNumber() / 1_000_000;
  console.log(`Bounty NB-${event.bountyNumber.toString().padStart(4, '0')} created`);
  console.log(`Reward: ${usdcAmount} USDC`);
  console.log(`Deadline: ${new Date(event.deadline.toNumber() * 1000).toISOString()}`);
});

BountySubmissionCreated

Emitted when a researcher submits their NKA to a bounty. Location: lib.rs:552-557 Emitted by: submit_to_bounty (line 147)

Fields

bounty_number
u64
required
The sequential ID of the bounty receiving the submission.
specimen_number
u64
required
The sequential ID of the NKA being submitted.
researcher
Pubkey
required
The wallet address of the researcher submitting the NKA.

Code Reference

#[event]
pub struct BountySubmissionCreated {
    pub bounty_number: u64,
    pub specimen_number: u64,
    pub researcher: Pubkey,
}

Example Usage

Track bounty-NKA matching:
program.addEventListener('BountySubmissionCreated', (event) => {
  console.log(`NKA-${event.specimenNumber.toString().padStart(4, '0')} submitted to Bounty NB-${event.bountyNumber.toString().padStart(4, '0')}`);
  console.log('Researcher:', event.researcher.toString());
});

BountyFulfilled

Emitted when a bounty creator approves a submission and payouts are executed. Location: lib.rs:559-566 Emitted by: approve_bounty_submission (line 221)

Fields

bounty_number
u64
required
The sequential ID of the bounty being fulfilled.
specimen_number
u64
required
The sequential ID of the NKA that won the bounty.
researcher
Pubkey
required
The wallet address of the researcher receiving the payout.
payout
u64
required
The USDC amount paid to the researcher in base units (6 decimals). Equals reward_amount - fee.Example: 97500000 = 97.5 USDC
fee
u64
required
The USDC protocol fee paid to the treasury in base units (6 decimals).Example: 2500000 = 2.5 USDC (2.5% of 100 USDC)

Code Reference

#[event]
pub struct BountyFulfilled {
    pub bounty_number: u64,
    pub specimen_number: u64,
    pub researcher: Pubkey,
    pub payout: u64,
    pub fee: u64,
}

Example Usage

Monitor payouts and fee collection:
program.addEventListener('BountyFulfilled', (event) => {
  const researcherPayout = event.payout.toNumber() / 1_000_000;
  const treasuryFee = event.fee.toNumber() / 1_000_000;
  const total = researcherPayout + treasuryFee;
  
  console.log(`Bounty NB-${event.bountyNumber.toString().padStart(4, '0')} fulfilled`);
  console.log(`NKA-${event.specimenNumber.toString().padStart(4, '0')} won`);
  console.log(`Researcher payout: ${researcherPayout} USDC`);
  console.log(`Protocol fee: ${treasuryFee} USDC (${(treasuryFee/total*100).toFixed(2)}%)`);
});

BountyClosed

Emitted when a bounty creator closes a bounty and reclaims escrowed USDC. Location: lib.rs:568-573 Emitted by: close_bounty (line 267)

Fields

bounty_number
u64
required
The sequential ID of the bounty being closed.
creator
Pubkey
required
The wallet address of the bounty creator receiving the refund.
refunded_amount
u64
required
The USDC amount refunded to the creator in base units (6 decimals). Equals the vault’s balance at closure time.Example: 100000000 = 100 USDC

Code Reference

#[event]
pub struct BountyClosed {
    pub bounty_number: u64,
    pub creator: Pubkey,
    pub refunded_amount: u64,
}

Example Usage

Track bounty closures and refunds:
program.addEventListener('BountyClosed', (event) => {
  const refund = event.refundedAmount.toNumber() / 1_000_000;
  console.log(`Bounty NB-${event.bountyNumber.toString().padStart(4, '0')} closed`);
  console.log(`Refunded ${refund} USDC to creator`);
});

Event Summary Table

EventTriggerKey DataUse Case
ProtocolInitializedProtocol setupAuthority, fee rateTrack deployment, monitor fee changes
NullResultSubmittedNew NKASpecimen number, researcherNKA registry indexing, researcher analytics
BountyCreatedNew bountyBounty number, reward, deadlineBounty marketplace indexing, expiry monitoring
BountySubmissionCreatedNKA submitted to bountyBounty & specimen numbers, researcherMatch tracking, notification systems
BountyFulfilledApproval & payoutPayout breakdown, winnerPayment verification, fee analytics
BountyClosedBounty refundRefund amountLifecycle tracking, treasury accounting

Indexing Events

All events can be indexed using Anchor’s event listener:
import { Program, AnchorProvider } from '@coral-xyz/anchor';
import { Connection } from '@solana/web3.js';
import idl from './nullgraph.json';

const connection = new Connection('https://api.devnet.solana.com');
const provider = new AnchorProvider(connection, wallet, {});
const program = new Program(idl, provider);

// Listen to all events
const listener = program.addEventListener('NullResultSubmitted', (event, slot) => {
  console.log(`[Slot ${slot}] New NKA:`, event);
});

// Remove listener when done
program.removeEventListener(listener);
For production indexing, consider using:
  • Helius or QuickNode webhooks for real-time event streams
  • The Graph protocol for decentralized indexing
  • Custom RPC polling with getProgramAccounts + transaction parsing

Build docs developers (and LLMs) love