Entros_docs
Integrate

Read on-chain (no SDK)

Direct PDA read for server actions, edge functions, Anchor programs, and any non-JS context.

The on-chain Anchor PDA is the source of truth for every other read path. Going directly to it removes one layer of dependency and works in any environment that can call a Solana RPC.

The TypeScript pattern

The same code path as the quickstart, shown here as a complete server action:

app/actions/check-verification.ts
"use server";

import { Connection, PublicKey } from "@solana/web3.js";

const ENTROS_ANCHOR_PROGRAM_ID = new PublicKey(
  "GZYwTp2ozeuRA5Gof9vs4ya961aANcJBdUzB7LN6q4b2",
);

const RPC_URL = process.env.SOLANA_RPC_URL ?? "https://api.devnet.solana.com";

export async function checkVerification(
  walletBase58: string,
  minScore = 100,
  maxAgeSeconds = 86_400,
): Promise<{ verified: boolean; score: number | null }> {
  const wallet = new PublicKey(walletBase58);
  const [pda] = PublicKey.findProgramAddressSync(
    [Buffer.from("identity"), wallet.toBuffer()],
    ENTROS_ANCHOR_PROGRAM_ID,
  );

  const account = await new Connection(RPC_URL).getAccountInfo(pda);
  if (!account) return { verified: false, score: null };

  const lastVerifiedAt = Number(account.data.readBigInt64LE(48));
  const score = account.data.readUInt16LE(60);
  const age = Math.floor(Date.now() / 1000) - lastVerifiedAt;

  return { verified: score >= minScore && age <= maxAgeSeconds, score };
}

The Rust pattern

For an Anchor program that gates an instruction on Entros verification, declare the IdentityState PDA as a read-only account constraint and inspect the score in the instruction body:

use anchor_lang::prelude::*;

declare_id!("YourProgram11111111111111111111111111111111");

const ENTROS_ANCHOR: Pubkey = pubkey!("GZYwTp2ozeuRA5Gof9vs4ya961aANcJBdUzB7LN6q4b2");

#[derive(Accounts)]
pub struct DoSomething<'info> {
    pub user: Signer<'info>,

    #[account(
        seeds = [b"identity", user.key().as_ref()],
        bump,
        seeds::program = ENTROS_ANCHOR,
    )]
    /// CHECK: PDA owned by entros-anchor; we read the trust_score field manually.
    pub identity_state: AccountInfo<'info>,
}

pub fn do_something(
    ctx: Context<DoSomething>,
    min_score: u16,
    max_age_secs: i64,
) -> Result<()> {
    let data = ctx.accounts.identity_state.try_borrow_data()?;
    let last_verified = i64::from_le_bytes(data[48..56].try_into().unwrap());
    let trust_score = u16::from_le_bytes(data[60..62].try_into().unwrap());

    let now = Clock::get()?.unix_timestamp;
    require!(trust_score >= min_score, ErrorCode::InsufficientTrust);
    require!(
        now.saturating_sub(last_verified) <= max_age_secs,
        ErrorCode::VerificationExpired
    );
    Ok(())
}

The PDA is owned by entros-anchor; your program reads its bytes but does not write to it.

The Python pattern

from solders.pubkey import Pubkey
from solana.rpc.api import Client

ENTROS_ANCHOR = Pubkey.from_string("GZYwTp2ozeuRA5Gof9vs4ya961aANcJBdUzB7LN6q4b2")

def read_anchor(client: Client, wallet: Pubkey) -> tuple[int, int] | None:
    """Returns (trust_score, last_verified_at) or None if never verified."""
    pda, _ = Pubkey.find_program_address([b"identity", bytes(wallet)], ENTROS_ANCHOR)
    info = client.get_account_info(pda).value
    if info is None:
        return None
    last_verified_at = int.from_bytes(info.data[48:56], "little", signed=True)
    trust_score = int.from_bytes(info.data[60:62], "little")
    return trust_score, last_verified_at

What you cannot do without the SDK

  • Verification. Submitting a new proof requires the Pulse SDK's capture and proof-generation pipeline. There is no direct path to write to the Anchor PDA without going through the verifier program.
  • Attestation issuance. SAS attestations are issued by the Entros executor on successful verification. Direct issuance from a client is not a supported path.

The read patterns above cover scoring, display, and gating. Read both fields: trust_score for how consistently a wallet has verified, and last_verification_timestamp for how long ago it last did.

For a claim, a vote, or anything else worth the friction, have the client run a verification at the point of the action so the Anchor you read was written moments earlier. Writes go through the SDK.

Where to look next

On this page