Skip to main content
Solana The AttestProtocol Solana contract provides a robust attestation system built on the Anchor framework, utilizing Program Derived Addresses (PDAs) for secure and deterministic account management.

Contract Architecture

Core Program Structure

The Solana attestation contract is implemented as an Anchor program with the following key components: Program ID: BMr9aui54YuxtpBzWXiFNmnr2iH6etRu7rMFJnKxjtpY
#[program]
pub mod attest {
    use super::*;

    // Core attestation functions
    pub fn attest(ctx: Context<Attest>, data: String, ref_uid: Option<Pubkey>, expiration_time: Option<u64>, revocable: bool) -> Result<()>
    pub fn delegated_attest(ctx: Context<DelegatedAttest>, attestation_data: AttestationData, attester_info: AttesterInfo, recipient: Pubkey, attester: Pubkey) -> Result<()>
    pub fn revoke(ctx: Context<Revoke>, schema_uid: Pubkey, recipient: Pubkey) -> Result<()>
    
    // Authority management
    pub fn register_authority(ctx: Context<RegisterAuthority>) -> Result<()>
    pub fn verify_authority(ctx: Context<VerifyAuthority>, is_verified: bool) -> Result<()>
    
    // Schema operations
    pub fn create_schema(ctx: Context<CreateSchema>, schema_name: String, schema: String, resolver: Option<Pubkey>, revocable: bool, levy: Option<Levy>) -> Result<()>
}

Account Structures

Attestation Account

The core attestation data structure with comprehensive metadata tracking:
#[account]
pub struct Attestation {
    pub schema: Pubkey,              // Schema UID (PDA) - 32 bytes
    pub recipient: Pubkey,           // Attestation recipient - 32 bytes  
    pub attester: Pubkey,            // Attestation creator - 32 bytes
    pub data: String,                // Custom attestation data - variable
    pub time: u64,                   // Creation timestamp - 8 bytes
    pub ref_uid: Option<Pubkey>,     // Reference to related attestation - 33 bytes
    pub expiration_time: Option<u64>, // Optional expiration - 9 bytes
    pub revocation_time: Option<u64>, // Revocation timestamp - 9 bytes
    pub revocable: bool,             // Revocation capability - 1 byte
    pub uid: Pubkey,                 // Unique attestation ID (PDA) - 32 bytes
}

impl Attestation {
    pub const MAX_DATA_SIZE: usize = 1000;
    pub const LEN: usize = 8 + 32 + 32 + 32 + 4 + Self::MAX_DATA_SIZE + 8 + 33 + 9 + 9 + 1 + 32;
}

Schema Data Structure

Schema definitions with flexible validation and resolver support:
#[account]
pub struct SchemaData {
    pub uid: Pubkey,              // Schema unique identifier (PDA)
    pub schema: String,           // Schema definition (JSON, XML, etc.)
    pub resolver: Option<Pubkey>, // Optional resolver contract
    pub revocable: bool,          // Schema revocation capability
    pub deployer: Pubkey,         // Authority who created schema
    pub levy: Option<Levy>,       // Optional fee structure
}

#[account]
pub struct Levy {
    pub amount: u64,              // Fee amount
    pub asset: Option<Pubkey>,    // Fee token (None = SOL)
    pub recipient: Pubkey,        // Fee recipient
}

Authority Management

Authority registration and verification system:
#[account]
pub struct AuthorityRecord {
    pub authority: Pubkey,        // Authority public key
    pub is_verified: bool,        // Admin verification status
    pub first_deployment: i64,    // Initial schema deployment timestamp
}

Core Operations

Attestation Creation

Standard Attestation Create attestations with flexible data and optional references:
pub fn attest(
    ctx: Context<Attest>,
    data: String,                  // Attestation data content
    ref_uid: Option<Pubkey>,       // Optional reference to existing attestation
    expiration_time: Option<u64>,  // Optional expiration timestamp
    revocable: bool                // Whether attestation can be revoked
) -> Result<()>
Delegated Attestation Allow third-party attestation creation with cryptographic verification:
pub fn delegated_attest(
    ctx: Context<DelegatedAttest>,
    attestation_data: AttestationData,  // Structured attestation data
    attester_info: AttesterInfo,        // Cryptographic proof of authorization
    recipient: Pubkey,                  // Target of attestation
    attester: Pubkey                    // Original attester
) -> Result<()>

#[account]
pub struct AttesterInfo {
    pub message: Vec<u8>,         // Signed message
    pub pubkey: [u8; 32],         // Attester public key
    pub signature: [u8; 64],      // Ed25519 signature
}

Schema Management

Schema Creation Define attestation templates with validation rules:
pub fn create_schema(
    ctx: Context<CreateSchema>,
    schema_name: String,           // Human-readable schema identifier
    schema: String,                // Schema definition (structured data)
    resolver: Option<Pubkey>,      // Optional validation contract
    revocable: bool,               // Schema-level revocation setting
    levy: Option<Levy>             // Optional fee structure
) -> Result<()>

Authority Operations

Authority Registration Self-registration for schema creation permissions:
pub fn register_authority(ctx: Context<RegisterAuthority>) -> Result<()>
Authority Verification Admin-controlled verification system:
pub fn verify_authority(
    ctx: Context<VerifyAuthority>, 
    is_verified: bool              // Verification status
) -> Result<()>

PDA Architecture

Account Derivation

The contract uses deterministic PDA generation for secure account management: Attestation PDA Seeds:
  • "attestation"
  • Schema UID bytes
  • Recipient public key bytes
  • Optional reference string bytes
Schema PDA Seeds:
  • "schema"
  • Authority public key bytes
  • Schema name bytes
Authority PDA Seeds:
  • "authority"
  • Authority public key bytes

Benefits of PDA Usage

  • Deterministic Addresses: Predictable account locations
  • No Private Keys: PDAs cannot sign transactions
  • Cross-Program Invocation: Secure program-to-program calls
  • Efficient Lookups: Direct address calculation without indexing

Security Features

Access Control

  • Authority Verification: Only verified authorities can create schemas
  • Attestation Ownership: Only attesters can revoke their attestations
  • Schema Enforcement: Attestations must reference valid schemas

Cryptographic Verification

  • Ed25519 Signatures: For delegated attestations
  • PDA Verification: Automatic validation of derived addresses
  • Replay Protection: Nonce-based duplicate prevention

Data Integrity

  • Immutable Attestations: Core attestation data cannot be modified
  • Revocation Tracking: Explicit revocation timestamps
  • Schema Validation: Resolver contract integration

Fee Structure

Levy System

Optional fee collection for schema operations:
#[account]
pub struct Levy {
    pub amount: u64,              // Fee amount in lamports or tokens
    pub asset: Option<Pubkey>,    // Token mint (None = SOL)
    pub recipient: Pubkey,        // Fee collection address
}

Fee Collection

  • Schema Creation: Optional levy on schema deployment
  • Attestation Fees: Per-attestation charges
  • Token Support: SOL and SPL token payments
  • Flexible Recipients: Configurable fee destinations

Error Handling

Custom Error Types

The contract implements comprehensive error handling:
// Common error scenarios
- InvalidSchema: Schema not found or invalid
- AccessDenied: Insufficient permissions
- AlreadyRevoked: Attestation previously revoked
- NotRevocable: Attempt to revoke non-revocable attestation
- ExpiredAttestation: Attestation past expiration time
- InvalidSignature: Failed cryptographic verification

Events

Attestation Events

Track attestation lifecycle with detailed events:
// Attestation created
AttestationCreated {
    attestation_uid: Pubkey,
    schema_uid: Pubkey,
    recipient: Pubkey,
    attester: Pubkey,
    timestamp: u64
}

// Attestation revoked  
AttestationRevoked {
    attestation_uid: Pubkey,
    revoker: Pubkey,
    timestamp: u64
}

Schema Events

Track schema management operations:
// Schema deployed
SchemaCreated {
    schema_uid: Pubkey,
    authority: Pubkey,
    revocable: bool
}

// Authority verified
AuthorityVerified {
    authority: Pubkey,
    verified: bool
}

Integration Patterns

Client Integration

JavaScript/TypeScript
import { Program, AnchorProvider } from '@coral-xyz/anchor';
import { Connection, PublicKey } from '@solana/web3.js';

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

// Create attestation
const attestTx = await program.methods
  .attest(
    attestationData,
    null,           // ref_uid
    null,           // expiration_time  
    true            // revocable
  )
  .accounts({
    attestation: attestationPda,
    schema: schemaPda,
    attester: wallet.publicKey,
    recipient: recipientKey,
    systemProgram: SystemProgram.programId,
  })
  .rpc();

Rust Integration

use anchor_client::{Client, Cluster};
use solana_sdk::{pubkey::Pubkey, signature::Keypair};

// Initialize client
let client = Client::new(Cluster::Devnet, Rc::new(keypair));
let program = client.program(program_id);

// Create attestation
let tx = program
    .request()
    .accounts(Attest {
        attestation: attestation_pda,
        schema: schema_pda,
        attester: keypair.pubkey(),
        recipient: recipient_key,
        system_program: system_program::ID,
    })
    .args(AttestInstruction::Attest {
        data: attestation_data,
        ref_uid: None,
        expiration_time: None,
        revocable: true,
    })
    .send()?;

Deployment Information

Network Addresses

NetworkProgram IDStatus
DevnetBMr9aui54YuxtpBzWXiFNmnr2iH6etRu7rMFJnKxjtpYActive
MainnetTBDPlanned

Build Instructions

# Clone repository
git clone https://github.com/daccred/attest.so.git
cd attest.so/contracts/solana

# Install dependencies
yarn install

# Build program
anchor build

# Run tests
anchor test

# Deploy to devnet
anchor deploy --provider.cluster devnet

Next Steps