cosmos_client/
signer.rs

1use crate::error::CosmosClient;
2use cosmrs::bip32::{Language, Mnemonic, XPrv};
3use cosmrs::crypto::secp256k1::SigningKey;
4use cosmrs::crypto::PublicKey;
5use cosmrs::AccountId;
6use hex::decode;
7use rand_core::OsRng;
8
9pub struct Signer {
10    pub mnemonic: Option<String>,
11    pub denom: String,
12    pub public_address: AccountId,
13    pub private_key: SigningKey,
14    pub public_key: PublicKey,
15    pub gas_adjustment_percent: u8,
16    pub gas_price: u128,
17}
18
19impl Signer {
20    fn load_from_mnemonic(
21        phrase: &str,
22        prefix: &str,
23        derivation: Option<&str>,
24    ) -> Result<(SigningKey, PublicKey, AccountId), CosmosClient> {
25        let derivation = if let Some(derivation) = derivation {
26            derivation
27        } else {
28            "m/44'/118'/0'/0/0"
29        };
30
31        let mnemonic = Mnemonic::new(phrase, Language::English)?;
32        let pri = XPrv::derive_from_path(&mnemonic.to_seed(""), &derivation.parse()?)?;
33        let private_key = SigningKey::from(pri);
34        let public_key = private_key.public_key();
35        let public_address = public_key.account_id(prefix)?;
36
37        Ok((private_key, public_key, public_address))
38    }
39
40    /// # Errors
41    ///
42    /// Will return `Err` if :
43    /// - we cannot parse the derivation
44    /// - if the prefix is bad
45    pub fn generate(
46        prefix: &str,
47        denom: &str,
48        derivation: Option<&str>,
49        gas_adjustment_percent: u8,
50        gas_price: u128,
51    ) -> Result<Self, CosmosClient> {
52        let mnemonic = Mnemonic::random(OsRng, Language::English);
53        let (private_key, public_key, public_address) =
54            Signer::load_from_mnemonic(mnemonic.phrase(), prefix, derivation)?;
55
56        Ok(Signer {
57            mnemonic: Some(mnemonic.phrase().to_string()),
58            public_address,
59            gas_adjustment_percent,
60            gas_price,
61            denom: denom.to_string(),
62            private_key,
63            public_key,
64        })
65    }
66
67    /// # Errors
68    ///
69    /// Will return `Err` if :
70    /// - the private key is invalid
71    /// - we cannot parse the derivation
72    /// - if the prefix is bad
73    pub fn from_pkey(
74        private_key: &str,
75        prefix: &str,
76        denom: &str,
77        gas_adjustment_percent: u8,
78        gas_price: u128,
79    ) -> Result<Self, CosmosClient> {
80        let private_key = SigningKey::from_slice(decode(private_key)?.as_slice())?;
81        let public_key = private_key.public_key();
82        let public_address = public_key.account_id(prefix)?;
83
84        Ok(Signer {
85            mnemonic: None,
86            public_address,
87            gas_adjustment_percent,
88            gas_price,
89            denom: denom.to_string(),
90            private_key,
91            public_key,
92        })
93    }
94
95    /// # Errors
96    ///
97    /// Will return `Err` if :
98    /// - mnemonic is invalid
99    /// - we cannot parse the derivation
100    /// - if the prefix is bad
101    pub fn from_mnemonic(
102        phrase: &str,
103        prefix: &str,
104        denom: &str,
105        derivation: Option<&str>,
106        gas_adjustment_percent: u8,
107        gas_price: u128,
108    ) -> Result<Self, CosmosClient> {
109        let (private_key, public_key, public_address) =
110            Signer::load_from_mnemonic(phrase, prefix, derivation)?;
111
112        Ok(Signer {
113            mnemonic: Some(phrase.to_string()),
114            public_address,
115            gas_adjustment_percent,
116            gas_price,
117            denom: denom.to_string(),
118            private_key,
119            public_key,
120        })
121    }
122}