solana_remote_wallet/
remote_keypair.rs

1use {
2    crate::{
3        ledger::get_ledger_from_info,
4        locator::{Locator, Manufacturer},
5        remote_wallet::{
6            RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager,
7            RemoteWalletType,
8        },
9    },
10    solana_derivation_path::DerivationPath,
11    solana_pubkey::Pubkey,
12    solana_signature::Signature,
13    solana_signer::{Signer, SignerError},
14};
15
16pub struct RemoteKeypair {
17    pub wallet_type: RemoteWalletType,
18    pub derivation_path: DerivationPath,
19    pub pubkey: Pubkey,
20    pub path: String,
21}
22
23impl RemoteKeypair {
24    pub fn new(
25        wallet_type: RemoteWalletType,
26        derivation_path: DerivationPath,
27        confirm_key: bool,
28        path: String,
29    ) -> Result<Self, RemoteWalletError> {
30        let pubkey = match &wallet_type {
31            RemoteWalletType::Ledger(wallet) => wallet.get_pubkey(&derivation_path, confirm_key)?,
32        };
33
34        Ok(Self {
35            wallet_type,
36            derivation_path,
37            pubkey,
38            path,
39        })
40    }
41}
42
43impl Signer for RemoteKeypair {
44    fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
45        Ok(self.pubkey)
46    }
47
48    fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError> {
49        match &self.wallet_type {
50            RemoteWalletType::Ledger(wallet) => wallet
51                .sign_message(&self.derivation_path, message)
52                .map_err(|e| e.into()),
53        }
54    }
55
56    fn is_interactive(&self) -> bool {
57        true
58    }
59}
60
61pub fn generate_remote_keypair(
62    locator: Locator,
63    derivation_path: DerivationPath,
64    wallet_manager: &RemoteWalletManager,
65    confirm_key: bool,
66    keypair_name: &str,
67) -> Result<RemoteKeypair, RemoteWalletError> {
68    let remote_wallet_info = RemoteWalletInfo::parse_locator(locator);
69    if remote_wallet_info.manufacturer == Manufacturer::Ledger {
70        let ledger = get_ledger_from_info(remote_wallet_info, keypair_name, wallet_manager)?;
71        let path = format!("{}{}", ledger.pretty_path, derivation_path.get_query());
72        Ok(RemoteKeypair::new(
73            RemoteWalletType::Ledger(ledger),
74            derivation_path,
75            confirm_key,
76            path,
77        )?)
78    } else {
79        Err(RemoteWalletError::DeviceTypeMismatch)
80    }
81}