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