layer_climb_address/
key.rs1use super::signer::TxSigner;
2use anyhow::{anyhow, Context, Result};
3use async_trait::async_trait;
4use bip32::DerivationPath;
5use bip39::Mnemonic;
6use signature::Signer;
7use std::{str::FromStr, sync::LazyLock};
8
9pub type PublicKey = tendermint::PublicKey;
10
11pub static COSMOS_HUB_PATH: LazyLock<DerivationPath> =
13 LazyLock::new(|| DerivationPath::from_str("m/44'/118'/0'/0/0").unwrap());
14
15pub fn cosmos_hub_derivation(index: u32) -> Result<DerivationPath> {
16 DerivationPath::from_str(&format!("m/44'/118'/0'/0/{}", index))
17 .map_err(|err| anyhow!("{}", err))
18}
19
20pub struct KeySigner {
21 pub key: bip32::XPrv,
22}
23
24impl KeySigner {
25 pub fn new_mnemonic_iter<I, S>(mnemonic: I, derivation: Option<&DerivationPath>) -> Result<Self>
26 where
27 I: IntoIterator<Item = S>,
28 S: AsRef<str>,
29 {
30 let mut joined_str = String::new();
31 for word in mnemonic {
32 joined_str.push_str(word.as_ref());
33 joined_str.push(' ');
34 }
35
36 Self::new_mnemonic_str(&joined_str, derivation)
37 }
38
39 pub fn new_mnemonic_str(mnemonic: &str, derivation: Option<&DerivationPath>) -> Result<Self> {
40 let derivation = derivation.unwrap_or(&COSMOS_HUB_PATH);
41 let mnemonic: Mnemonic = mnemonic.parse()?;
42 let seed = mnemonic.to_seed("");
43 let key =
44 bip32::XPrv::derive_from_path(seed, derivation).map_err(|err| anyhow!("{}", err))?;
45
46 Ok(Self { key })
47 }
48}
49
50cfg_if::cfg_if! {
51 if #[cfg(target_arch = "wasm32")] {
52 #[async_trait(?Send)]
53 impl TxSigner for KeySigner {
54 async fn sign(&self, msg: &layer_climb_proto::tx::SignDoc) -> Result<Vec<u8>> {
55 sign(self, msg).await
56 }
57
58 async fn public_key(&self) -> Result<PublicKey> {
59 public_key(self).await
60 }
61 }
62
63 } else {
64 #[async_trait]
65 impl TxSigner for KeySigner {
66 async fn sign(&self, msg: &layer_climb_proto::tx::SignDoc) -> Result<Vec<u8>> {
67 sign(self, msg).await
68 }
69
70 async fn public_key(&self) -> Result<PublicKey> {
71 public_key(self).await
72 }
73 }
74 }
75}
76
77async fn sign(signer: &KeySigner, msg: &layer_climb_proto::tx::SignDoc) -> Result<Vec<u8>> {
78 let signed: k256::ecdsa::Signature = signer
79 .key
80 .private_key()
81 .try_sign(&layer_climb_proto::proto_into_bytes(msg)?)
82 .map_err(|err| anyhow!("{}", err))?;
83 Ok(signed.to_vec())
84}
85
86async fn public_key(signer: &KeySigner) -> Result<PublicKey> {
87 let public_key = signer.key.public_key();
88 let public_key_bytes = public_key.to_bytes();
89 PublicKey::from_raw_secp256k1(&public_key_bytes).context("Invalid secp256k1 public key")
90}