NextDotID / relation_server

RelationService: relation aggregation.
https://docs.next.id
8 stars 6 forks source link

Add Platform::`Solana` & `SNS` #127

Closed ZhongFuze closed 6 months ago

nykma commented 6 months ago

Solana name service: https://www.sns.id

ZhongFuze commented 6 months ago

https://github.com/NextDotID/relation_server/pull/128

Add Solana Name Service (SNS) to RelationService Upsteam

Docs: https://github.com/Bonfida/sns-sdk/tree/main?tab=readme-ov-file#rust Cargo.toml Notice: If sns-sdk version=1.4.0,other depends should version<1.16.0 (Must not upgrade to 1.16.16)

solana-sdk = "<1.16.0"
solana-client = "~1.14.1"
spl-name-service = { version = "0.2.0", features = ["no-entrypoint"] }
spl-token = "3.0.0"
solana-account-decoder = "<1.16.0"
solana-program = "<1.16.0"
sns-sdk = "=1.4.0"
borsh = "0.9"

Twitter Handle

Independent query Twitter handle binding. https://sns.guide/domain-name/wallet-guide/twitter-handles.html

There aren't two twitter handle methods in the Rust SDK. Using the JavaScript library as a guide, I replicated and encapsulated get_twitter_registry and get_handle_and_registry_key.

lazy_static! {
    pub static ref TWITTER_VERIFICATION_AUTHORITY: Pubkey =
        Pubkey::from_str("FvPH7PrVrLGKPfqaf3xJodFTjZriqrAXXLTVWEorTFBi")
            .expect("Invalid public key");
    pub static ref TWITTER_ROOT_PARENT_REGISTRY_KEY: Pubkey =
        Pubkey::from_str("4YcexoW3r78zz16J2aqmukBLRwGq6rAvWzJpkYAXqebv")
            .expect("Invalid public key");
}

Direct look up

To find the Twitter handle associated to a public key

async fn get_handle_and_registry_key(
    rpc_client: &RpcClient,
    pubkey: &str,
) -> Result<Option<String>, Error> {
    let verified_pubkey = Pubkey::from_str(pubkey)?;
    let hashed_verified_pubkey = get_hashed_name(&verified_pubkey.to_string());
    let (reverse_registry_key, _) = get_seeds_and_key(
        &spl_name_service::id(),
        hashed_verified_pubkey,
        Some(&TWITTER_VERIFICATION_AUTHORITY),
        Some(&TWITTER_ROOT_PARENT_REGISTRY_KEY),
    );

    let ascii_start_index = 33; // Starting index of "dansform"
    let handle = match resolve_name_registry(rpc_client, &reverse_registry_key).await? {
        Some((_, vec_u8)) => {
            // Skip null bytes at the beginning of the ASCII part
            let ascii_part = &vec_u8[ascii_start_index..];
            let trimmed_ascii_part = ascii_part
                .iter()
                .skip_while(|&&byte| byte == 0)
                .cloned()
                .collect::<Vec<u8>>();
            Some(deserialize_record_v2_content(
                &trimmed_ascii_part,
                Record::Twitter,
            )?)
        }
        None => None,
    };
    Ok(handle)
}

Reverse look up

To find the public key associated to a Twitter handle

async fn get_twitter_registry(
    rpc_client: &RpcClient,
    twitter_handle: &str,
) -> Result<Option<Pubkey>, Error> {
    let hashed_twitter_handle = get_hashed_name(twitter_handle);
    let (twitter_handle_registry_key, _) = get_seeds_and_key(
        &spl_name_service::id(),
        hashed_twitter_handle,
        None, // Assuming no name class
        Some(&TWITTER_ROOT_PARENT_REGISTRY_KEY),
    );
    // Some(NameRecordHeader { parent_name: 4YcexoW3r78zz16J2aqmukBLRwGq6rAvWzJpkYAXqebv, owner: CLnUobvN8Fy7vhDMkQqNF7STxk5CT7MoePXvkgUGgdc9, class: 11111111111111111111111111111111 })
    match resolve_name_registry(rpc_client, &twitter_handle_registry_key).await? {
        Some((header, _)) => Ok(Some(header.owner)),
        None => Ok(None),
    }
}