use super::{Address, PrivateKey, PublicKey};
use crate::keyring::{KeyCodec, Keyring as GenericKeyring, SubstrateKeystore};
use anyhow::{Result, anyhow};
use core::str::FromStr;
use serde::{Deserialize, Serialize};
use sp_core::crypto::Pair as PairTrait;
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
pub struct Secp256k1Codec;
impl KeyCodec for Secp256k1Codec {
type Pair = sp_core::ecdsa::Pair;
type PrivateKey = PrivateKey;
type PublicKey = PublicKey;
type Address = Address;
const KEY_TYPE: &'static str = "ecdsa";
fn derive_public(private_key: &Self::PrivateKey) -> Self::PublicKey {
private_key.public_key()
}
fn derive_address(public_key: &Self::PublicKey) -> Result<Self::Address> {
Ok(Address::from(*public_key))
}
fn encode_private(private_key: &Self::PrivateKey) -> Result<String> {
Ok(hex::encode(private_key.seed().as_ref()))
}
fn decode_private(encoded: &str) -> Result<Self::PrivateKey> {
PrivateKey::from_str(encoded).map_err(|err| anyhow!("Invalid private key: {err}"))
}
fn encode_public(public_key: &Self::PublicKey) -> Result<String> {
Ok(format!("0x{}", public_key.to_hex()))
}
fn decode_public(encoded: &str) -> Result<Self::PublicKey> {
PublicKey::from_str(encoded).map_err(|err| anyhow!("Invalid public key: {err}"))
}
fn encode_address(address: &Self::Address) -> Result<String> {
Ok(format!("0x{}", address.to_hex()))
}
fn decode_address(encoded: &str) -> Result<Self::Address> {
Address::from_str(encoded).map_err(|err| anyhow!("Invalid address: {err}"))
}
fn random_private() -> Result<Self::PrivateKey> {
Ok(PrivateKey::random())
}
fn import_suri(suri: &str, password: Option<&str>) -> Result<Self::PrivateKey> {
let (pair, _) = sp_core::ecdsa::Pair::from_string_with_seed(suri, password)
.map_err(|e| anyhow!("Invalid SURI: {e:?}"))?;
Ok(pair.into())
}
}
pub type Keystore = SubstrateKeystore<Secp256k1Codec>;
pub type Keyring = GenericKeyring<Keystore>;
#[cfg(test)]
mod tests {
use super::*;
use crate::keyring::KeystoreEntry;
#[test]
fn create_and_recover_private_key() {
let temp_dir = tempfile::tempdir().unwrap();
let mut keyring = Keyring::load(temp_dir.path().to_path_buf()).unwrap();
let (keystore, private_key) = keyring.create("alice", None).unwrap();
assert_eq!(keystore.name, "alice");
assert_eq!(keyring.list().len(), 1);
assert_eq!(keyring.list()[0].name(), "alice");
assert_eq!(keystore.private_key().unwrap(), private_key);
}
}