sol-chainsaw 0.0.2

Deserializing Solana accounts using their progam IDL
Documentation
use solana_program::{hash::hash, pubkey::Pubkey};

use crate::{ChainsawResult, IdlProvider};

pub type DiscriminatorBytes = [u8; 8];

/// Derives the account discriminator form the account name using the same algorithm that anchor
/// uses.
pub fn account_discriminator(name: &str) -> DiscriminatorBytes {
    let mut discriminator = [0u8; 8];
    let hashed = hash(format!("account:{}", name).as_bytes()).to_bytes();
    discriminator.copy_from_slice(&hashed[..8]);
    discriminator
}

const ANCHOR_SEED: &str = "anchor:idl";
const SHANK_SEED: &str = "shank:idl";

/// Resolves the address of the account where the program [IDL] is stored.
///
/// - [provider] that uploaded the [IDL]
/// - [program_id] address of the program
pub fn try_idl_address(
    provider: &IdlProvider,
    program_id: &Pubkey,
) -> ChainsawResult<Pubkey> {
    let (base, _) = Pubkey::find_program_address(&[], program_id);
    let seed = match provider {
        IdlProvider::Anchor => ANCHOR_SEED,
        IdlProvider::Shank => SHANK_SEED,
    };
    let key = Pubkey::create_with_seed(&base, seed, program_id)?;
    Ok(key)
}

#[cfg(test)]
mod test {
    use std::str::FromStr;

    use super::*;

    pub fn str_to_pubkey(pubkey_str: &str) -> Pubkey {
        FromStr::from_str(pubkey_str).expect("pubkey from string")
    }

    #[test]
    fn account_discriminator_test() {
        let name = "VaultInfo";
        let discriminator = account_discriminator(name);
        assert_eq!(discriminator, [133, 250, 161, 78, 246, 27, 55, 187]);
    }

    #[test]
    fn idl_address_test() {
        let program_id =
            str_to_pubkey("cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ");

        let anchor_idl_address =
            try_idl_address(&IdlProvider::Anchor, &program_id).unwrap();
        let shank_idl_address =
            try_idl_address(&IdlProvider::Shank, &program_id).unwrap();

        assert_eq!(
            anchor_idl_address.to_string(),
            "CggtNXgCye2qk7fLohonNftqaKT35GkuZJwHrRghEvSF"
        );
        assert_eq!(
            shank_idl_address.to_string(),
            "AEUhdmwzSea7oYDWhAiSBArqq6tBLFNNZZ448wfbaV3Z"
        );
    }
}