ai-registry 0.1.0

AI Registry on Solana - On-chain agent identity and knowledge management
Documentation
use ai_registry_api::{
    consts::{AGENT, MAX_URI_LENGTH},
    error::AgentError,
    event::IdentityProfileUpdatedEvent,
    instruction::UpdateIdentityProfile,
    state::Agent,
};
use steel::*;

/// Process an update identity profile instruction
pub fn process_update_identity_profile(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
    let args = UpdateIdentityProfile::try_from_bytes(data)?;

    // Load accounts (signer first, following Solana best practices)
    let [controller_info, agent_info] = accounts else {
        return Err(ProgramError::NotEnoughAccountKeys);
    };

    // Validate accounts
    agent_info.is_writable()?.has_seeds(
        &[
            AGENT,
            agent_info
                .as_account::<Agent>(&ai_registry_api::ID)?
                .creator
                .as_ref(),
        ],
        &ai_registry_api::ID,
    )?;
    controller_info.is_signer()?;

    // Load agent and verify controller
    let agent = agent_info.as_account::<Agent>(&ai_registry_api::ID)?;
    if controller_info.key != &agent.controller {
        return Err(AgentError::UnauthorizedController.into());
    }

    // Validate identity profile URI
    let uri_len = args
        .identity_profile_uri
        .iter()
        .position(|&b| b == 0)
        .unwrap_or(MAX_URI_LENGTH);
    let uri_bytes = &args.identity_profile_uri[..uri_len];
    if uri_bytes.is_empty() || uri_bytes.len() > MAX_URI_LENGTH {
        return Err(AgentError::InvalidLength.into());
    }

    let uri_str =
        core::str::from_utf8(uri_bytes).map_err(|_| AgentError::InvalidIdentityProfileUri)?;

    // Only allow https:// or ipfs:// schemes
    if !uri_str.starts_with("https://") && !uri_str.starts_with("ipfs://") {
        return Err(AgentError::InsecureUri.into());
    }

    // Update agent
    let clock = Clock::get()?;
    let agent = agent_info.as_account_mut::<Agent>(&ai_registry_api::ID)?;
    agent.identity_profile_uri = args.identity_profile_uri;
    agent.identity_profile_uri_len = uri_len as u8;
    agent.identity_profile_hash = args.identity_profile_hash;
    agent.updated_at = clock.unix_timestamp;

    // Create URI preview (first 32 bytes)
    let mut uri_preview = [0u8; 32];
    let preview_len = core::cmp::min(32, uri_len);
    uri_preview[..preview_len].copy_from_slice(&uri_bytes[..preview_len]);

    // Emit event
    IdentityProfileUpdatedEvent {
        creator: agent.creator,
        agent: *agent_info.key,
        identity_profile_uri_preview: uri_preview,
        identity_profile_hash: args.identity_profile_hash,
        timestamp: clock.unix_timestamp,
    }
    .log();

    Ok(())
}