Core Concepts
AttestationRecord
The AttestationRecord PDA is the wallet's public proof that it passed Althea verification. It's the account every dApp reads to gate features. Deterministic seeds make it derivable from any wallet address.
Account layout
AttestationRecord
#[account]
pub struct AttestationRecord {
pub verified: bool,
pub timestamp: i64, // unix seconds
pub protocol: [u8; 16], // "Althea-v1" + zero padding
pub revoked: bool,
pub bump: u8,
}
impl AttestationRecord {
pub const SIZE: usize = 1 + 8 + 16 + 1 + 1;
}Field semantics
- verified — always true on creation. The program only initialises this account on a successful proof submission.
- timestamp — Solana clock time at which the proof was accepted. Useful for "verified within last N days" policies.
- protocol — version tag, currently "Althea-v1". dApps can refuse older protocol versions in the future.
- revoked — set if the user has explicitly revoked their attestation (a future SDK call). Treated as verified: false by checkAttestation().
PDA seeds
PDA derivation
seeds = [b"africazk-attestation", wallet_pubkey.as_ref()]
program_id = AfricaZK1111111111111111111111111111111111Deriving the PDA in TypeScript
You almost never need to do this manually — checkAttestation() does it for you. But if you're composing Althea with another Anchor program, here is the canonical derivation:
derive.ts
import { PublicKey } from '@solana/web3.js'
const PROGRAM_ID = new PublicKey('AfricaZK1111111111111111111111111111111111')
export function deriveAttestationPDA(wallet: PublicKey) {
return PublicKey.findProgramAddressSync(
[Buffer.from('africazk-attestation'), wallet.toBuffer()],
PROGRAM_ID
)
}Lifecycle
- Initialised by submit_proof on first successful verification.
- Read by any dApp via checkAttestation().
- Optionally revoked by the user (future SDK version) — sets revoked = true.
- Permanent. The PDA itself is never closed; rent is paid once by the verifying user.