zingolabs-zewif 0.0.2

Fork of Blockhain Commons's zewif crate.
Documentation
use anyhow::{Context, Result};
use bc_envelope::prelude::*;

use crate::{MnemonicLanguage, NoQuotesDebugOption, SeedFingerprint};

#[derive(Clone, PartialEq)]
pub struct Bip39Mnemonic {
    mnemonic: String,
    language: Option<MnemonicLanguage>,
    fingerprint: Option<SeedFingerprint>,
}

impl std::fmt::Debug for Bip39Mnemonic {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("MnemonicSeed")
            .field("language", &NoQuotesDebugOption(&self.language))
            .field("mnemonic", &"<elided>".to_string())
            .field(
                "fingerprint",
                &NoQuotesDebugOption(&self.fingerprint.map(|f| f.to_hex())),
            )
            .finish()
    }
}

impl Bip39Mnemonic {
    pub fn new(mnemonic: impl AsRef<str>, language: Option<MnemonicLanguage>) -> Self {
        Self {
            mnemonic: mnemonic.as_ref().to_string(),
            language,
            fingerprint: None,
        }
    }

    pub fn set_fingerprint(&mut self, fingerprint: SeedFingerprint) {
        self.fingerprint = Some(fingerprint);
    }

    pub fn mnemonic(&self) -> &String {
        &self.mnemonic
    }

    pub fn set_mnemonic(&mut self, mnemonic: String) {
        self.mnemonic = mnemonic;
    }

    pub fn language(&self) -> Option<&MnemonicLanguage> {
        self.language.as_ref()
    }

    pub fn fingerprint(&self) -> Option<&SeedFingerprint> {
        self.fingerprint.as_ref()
    }

    pub fn set_language(&mut self, language: MnemonicLanguage) {
        self.language = Some(language);
    }
}

impl From<Bip39Mnemonic> for Envelope {
    fn from(value: Bip39Mnemonic) -> Self {
        Envelope::new(value.mnemonic)
            .add_type("Bip39Mnemonic")
            .add_optional_assertion("language", value.language)
            .add_optional_assertion("fingerprint", value.fingerprint)
    }
}

impl TryFrom<Envelope> for Bip39Mnemonic {
    type Error = anyhow::Error;

    fn try_from(envelope: Envelope) -> Result<Self, Self::Error> {
        envelope
            .check_type_envelope("Bip39Mnemonic")
            .context("Bip39Mnemonic")?;
        let mnemonic = envelope.extract_subject().context("mnemonic")?;
        let language = envelope
            .try_optional_object_for_predicate("language")
            .context("language")?;
        let fingerprint = envelope
            .try_optional_object_for_predicate("fingerprint")
            .context("fingerprint")?;
        Ok(Self {
            mnemonic,
            language,
            fingerprint,
        })
    }
}

#[cfg(test)]
mod tests {
    use crate::{MnemonicLanguage, SeedFingerprint, test_envelope_roundtrip};

    use super::Bip39Mnemonic;

    impl crate::RandomInstance for Bip39Mnemonic {
        fn random() -> Self {
            Self {
                mnemonic: String::random(),
                language: MnemonicLanguage::opt_random(),
                fingerprint: SeedFingerprint::opt_random(),
            }
        }
    }

    test_envelope_roundtrip!(Bip39Mnemonic);
}