subalfred-core 0.9.4

Subalfred's core libraries.
Documentation
//! Subalfred core SS58 library.

#[cfg(test)] mod test;

// subalfred
use crate::prelude::*;
use subcryptor::{Sr25519, ss58_registry::Ss58AddressFormat};

/// Network address.
#[cfg_attr(test, derive(Clone, PartialEq, Eq))]
#[derive(Debug)]
pub struct Address<'a> {
	/// Network name.
	pub network: &'a str,
	/// Network prefix.
	pub prefix: u16,
	/// Address value.
	pub value: String,
}

/// calculate the public key of the address and the network's corresponding address.
///
/// `address` could be a public key or SS58 address.
/// `network` is case insensitive.
pub fn of<'a>(address: &str, network: &'a str) -> Result<(Vec<u8>, String, Address<'a>)> {
	let public_key = recover_public_key(address)?;
	let hex_public_key = array_bytes::bytes2hex("0x", &public_key);
	let (prefix, address) = subcryptor::ss58_address_of(&public_key, network)
		.map_err(error::Ss58::CalculateSs58AddressFailed)?;

	Ok((public_key, hex_public_key, Address { network, prefix, value: address }))
}

/// calculate the public key and all the specific network addresses of the network.
///
/// `address` could be a public key or SS58 address.
pub fn all(address: &str) -> Result<(Vec<u8>, String, Vec<Address>)> {
	let public_key = recover_public_key(address)?;
	let hex_public_key = array_bytes::bytes2hex("0x", &public_key);
	let mut addresses = Vec::new();

	for network in Ss58AddressFormat::all_names() {
		let (prefix, address) = subcryptor::ss58_address_of(&public_key, network)
			.map_err(error::Ss58::CalculateSs58AddressFailed)?;

		addresses.push(Address { network, prefix, value: address });
	}

	Ok((public_key, hex_public_key, addresses))
}

// Recover the public key from the given address.
//
// `address` could be a public key or SS58 address.
// NO-OP, If the `address` is already a public key.
fn recover_public_key(address: &str) -> Result<Vec<u8>> {
	match address.len() {
		// TODO: support more key types
		47..=49 => Ok(subcryptor::public_key_of::<Sr25519>(address).map_err(|e| {
			error::Ss58::InvalidAddress {
				address: address.into(),
				source: Some(error::Ss58InvalidAddressSource::Subcryptor(e)),
			}
		})?),
		len => {
			if (len == 64 && !address.starts_with("0x")) || (len == 66 && address.starts_with("0x"))
			{
				Ok(array_bytes::hex2bytes(address).map_err(|e| error::Ss58::InvalidAddress {
					address: address.into(),
					source: Some(error::Ss58InvalidAddressSource::ArrayBytes(e)),
				})?)
			} else {
				Err(error::Ss58::InvalidAddress { address: address.into(), source: None })?
			}
		},
	}
}