use std::collections::HashMap;
use async_trait::async_trait;
use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
use crate::{
error::{Result, RialoError},
rpc::types::Pubkey,
};
type Keypair = SigningKey;
type PublicKey = VerifyingKey;
#[derive(Debug, PartialEq, Eq)]
pub struct DerivedKeypair {
pub index: u32,
pub pubkey: PublicKey,
keypair: Keypair,
derivation_path: Option<String>,
}
impl Clone for DerivedKeypair {
fn clone(&self) -> Self {
let keypair_bytes = self.keypair.to_bytes();
let keypair = Keypair::from_bytes(&keypair_bytes);
Self {
index: self.index,
pubkey: self.pubkey,
keypair,
derivation_path: self.derivation_path.clone(),
}
}
}
impl DerivedKeypair {
pub fn new(index: u32, keypair: Keypair, derivation_path: Option<String>) -> Self {
Self {
index,
pubkey: keypair.verifying_key(),
keypair,
derivation_path,
}
}
pub fn sign(&self, message: &[u8]) -> Signature {
self.keypair.sign(message)
}
pub fn verify_signature(&self, message: &[u8], signature: &Signature) -> bool {
self.pubkey.verify_strict(message, signature).is_ok()
}
pub fn pubkey_string(&self) -> String {
bs58::encode(self.pubkey.as_bytes()).into_string()
}
pub fn derivation_path(&self) -> Option<&str> {
self.derivation_path.as_deref()
}
pub fn keypair_bytes(&self) -> Vec<u8> {
self.keypair.as_bytes().to_vec()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Keyring {
pub name: String,
pub keypairs: HashMap<u32, DerivedKeypair>,
active_keypair_index: u32,
mnemonic: Option<String>,
}
impl Clone for Keyring {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
keypairs: self.keypairs.clone(),
active_keypair_index: self.active_keypair_index,
mnemonic: self.mnemonic.clone(),
}
}
}
impl Keyring {
pub fn new(
name: String,
keypair: Keypair,
mnemonic: Option<String>,
derivation_path: Option<String>,
) -> Self {
let mut keypairs = HashMap::new();
let default_keypair = DerivedKeypair::new(0, keypair, derivation_path);
keypairs.insert(0, default_keypair);
Self {
name,
keypairs,
active_keypair_index: 0,
mnemonic,
}
}
pub fn new_empty(name: impl ToString) -> Self {
let keypair = Keypair::generate(&mut rand::thread_rng());
Self::new(name.to_string(), keypair, None, None)
}
pub fn sign(&self, message: &[u8]) -> Signature {
self.active_keypair().sign(message)
}
pub fn verify_signature(&self, message: &[u8], signature: &Signature) -> bool {
self.active_keypair().verify_signature(message, signature)
}
pub fn pubkey_string(&self) -> String {
self.active_keypair().pubkey_string()
}
pub fn pubkey(&self) -> Pubkey {
Pubkey::new_from_array(self.active_keypair().pubkey.to_bytes())
}
pub fn keypair_bytes(&self) -> Vec<u8> {
self.active_keypair().keypair_bytes()
}
pub fn mnemonic(&self) -> Option<&str> {
self.mnemonic.as_deref()
}
pub fn active_keypair(&self) -> &DerivedKeypair {
self.keypairs
.get(&self.active_keypair_index)
.expect("Active keypair must exist")
}
pub fn set_active_keypair(&mut self, index: u32) -> Result<()> {
if self.keypairs.contains_key(&index) {
self.active_keypair_index = index;
Ok(())
} else {
Err(RialoError::Keyring("Keypair not found".to_string()))
}
}
pub fn get_keypair(&self, index: u32) -> Option<&DerivedKeypair> {
self.keypairs.get(&index)
}
pub fn add_keypair(&mut self, keypair: DerivedKeypair) {
self.keypairs.insert(keypair.index, keypair);
}
pub fn list_keypairs(&self) -> Vec<u32> {
self.keypairs.keys().cloned().collect()
}
pub fn get_keypairs(&self) -> Vec<String> {
self.keypairs
.values()
.map(|keypair| keypair.pubkey_string())
.collect()
}
pub fn derivation_path(&self) -> Option<&str> {
self.active_keypair().derivation_path()
}
pub fn sign_with_keypair(&self, message: &[u8], keypair_index: u32) -> Result<Signature> {
if let Some(keypair) = self.get_keypair(keypair_index) {
Ok(keypair.sign(message))
} else {
Err(RialoError::Keyring(format!(
"Keypair index {keypair_index} not found"
)))
}
}
#[deprecated(since = "0.2.0", note = "Use active_keypair() instead")]
pub fn active_account(&self) -> &DerivedKeypair {
self.active_keypair()
}
#[deprecated(since = "0.2.0", note = "Use set_active_keypair() instead")]
pub fn set_active_account(&mut self, index: u32) -> Result<()> {
self.set_active_keypair(index)
}
#[deprecated(since = "0.2.0", note = "Use get_keypair() instead")]
pub fn get_account(&self, index: u32) -> Option<&DerivedKeypair> {
self.get_keypair(index)
}
#[deprecated(since = "0.2.0", note = "Use add_keypair() instead")]
pub fn add_account(&mut self, keypair: DerivedKeypair) {
self.add_keypair(keypair)
}
#[deprecated(since = "0.2.0", note = "Use list_keypairs() instead")]
pub fn list_accounts(&self) -> Vec<u32> {
self.list_keypairs()
}
#[deprecated(since = "0.2.0", note = "Use get_keypairs() instead")]
pub fn get_accounts(&self) -> Vec<String> {
self.get_keypairs()
}
#[deprecated(since = "0.2.0", note = "Use sign_with_keypair() instead")]
pub fn sign_with_account(&self, message: &[u8], account_index: u32) -> Result<Signature> {
self.sign_with_keypair(message, account_index)
}
}
#[async_trait]
pub trait KeyringProvider: Send + Sync {
async fn create(&self, name: &str, password: &str) -> Result<Keyring>;
#[cfg(feature = "mnemonic")]
async fn create_with_mnemonic(&self, name: &str, password: &str) -> Result<Keyring>;
#[cfg(feature = "mnemonic")]
async fn recover_from_mnemonic(
&self,
name: &str,
mnemonic: &str,
password: &str,
) -> Result<Keyring>;
async fn load(&self, name: &str, password: &str) -> Result<Keyring>;
async fn list(&self) -> Result<Vec<String>>;
async fn exists(&self, name: &str) -> Result<bool>;
#[cfg(feature = "hd-wallet")]
async fn derive_keyring(
&self,
source_keyring_name: &str,
new_keyring_name: &str,
keypair_index: u32,
password: &str,
) -> Result<Keyring>;
async fn list_public_keys(&self) -> Result<Vec<(String, Pubkey)>>;
async fn list_keypairs(&self, keyring_name: &str) -> Result<Vec<(u32, Pubkey)>>;
async fn get_keypair_balance(&self, keyring_name: &str, keypair_index: u32) -> Result<u64>;
#[cfg(feature = "hd-wallet")]
async fn derive_keypair(
&self,
keyring_name: &str,
keypair_index: u32,
password: &str,
) -> Result<(u32, Pubkey)>;
async fn get_public_key(&self, name: &str) -> Result<Pubkey>;
async fn get_keypairs_info(&self, name: &str) -> Result<Vec<(u32, Pubkey)>>;
async fn get_keypair_public_key(&self, name: &str, keypair_index: u32) -> Result<Pubkey>;
async fn next_keypair_index(&self, name: &str) -> Result<u32>;
}
#[deprecated(since = "0.2.0", note = "Use Keyring instead")]
pub type Wallet = Keyring;
#[deprecated(since = "0.2.0", note = "Use DerivedKeypair instead")]
pub type Account = DerivedKeypair;
#[deprecated(since = "0.2.0", note = "Use KeyringProvider instead")]
pub trait WalletProvider: KeyringProvider {}
#[allow(deprecated)]
impl<T: KeyringProvider> WalletProvider for T {}