remote-wallet: Select hardware wallets based on host device path
This commit is contained in:
		
				
					committed by
					
						
						Trent Nelson
					
				
			
			
				
	
			
			
			
						parent
						
							2c38865e70
						
					
				
				
					commit
					8e3353d9ef
				
			@@ -339,6 +339,7 @@ impl RemoteWallet for LedgerWallet {
 | 
			
		||||
            .clone()
 | 
			
		||||
            .unwrap_or("Unknown")
 | 
			
		||||
            .to_string();
 | 
			
		||||
        let host_device_path = dev_info.path().to_string_lossy().to_string();
 | 
			
		||||
        let version = self.get_firmware_version()?;
 | 
			
		||||
        self.version = version;
 | 
			
		||||
        let pubkey_result = self.get_pubkey(&DerivationPath::default(), false);
 | 
			
		||||
@@ -350,6 +351,7 @@ impl RemoteWallet for LedgerWallet {
 | 
			
		||||
            model,
 | 
			
		||||
            manufacturer,
 | 
			
		||||
            serial,
 | 
			
		||||
            host_device_path,
 | 
			
		||||
            pubkey,
 | 
			
		||||
            error,
 | 
			
		||||
        })
 | 
			
		||||
@@ -521,17 +523,17 @@ pub fn get_ledger_from_info(
 | 
			
		||||
            return Err(device.error.clone().unwrap());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    let mut matches: Vec<(Pubkey, String)> = matches
 | 
			
		||||
    let mut matches: Vec<(String, String)> = matches
 | 
			
		||||
        .filter(|&device_info| device_info.error.is_none())
 | 
			
		||||
        .map(|device_info| (device_info.pubkey, device_info.get_pretty_path()))
 | 
			
		||||
        .map(|device_info| (device_info.host_device_path.clone(), device_info.get_pretty_path()))
 | 
			
		||||
        .collect();
 | 
			
		||||
    if matches.is_empty() {
 | 
			
		||||
        return Err(RemoteWalletError::NoDeviceFound);
 | 
			
		||||
    }
 | 
			
		||||
    matches.sort_by(|a, b| a.1.cmp(&b.1));
 | 
			
		||||
    let (pubkeys, device_paths): (Vec<Pubkey>, Vec<String>) = matches.into_iter().unzip();
 | 
			
		||||
    let (host_device_paths, device_paths): (Vec<Pubkey>, Vec<String>) = matches.into_iter().unzip();
 | 
			
		||||
 | 
			
		||||
    let wallet_base_pubkey = if pubkeys.len() > 1 {
 | 
			
		||||
    let wallet_host_device_path = if host_device_paths.len() > 1 {
 | 
			
		||||
        let selection = Select::with_theme(&ColorfulTheme::default())
 | 
			
		||||
            .with_prompt(&format!(
 | 
			
		||||
                "Multiple hardware wallets found. Please select a device for {:?}",
 | 
			
		||||
@@ -541,11 +543,11 @@ pub fn get_ledger_from_info(
 | 
			
		||||
            .items(&device_paths[..])
 | 
			
		||||
            .interact()
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        pubkeys[selection]
 | 
			
		||||
        &host_device_paths[selection]
 | 
			
		||||
    } else {
 | 
			
		||||
        pubkeys[0]
 | 
			
		||||
        &host_device_paths[0]
 | 
			
		||||
    };
 | 
			
		||||
    wallet_manager.get_ledger(&wallet_base_pubkey)
 | 
			
		||||
    wallet_manager.get_ledger(wallet_host_device_path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
 
 | 
			
		||||
@@ -152,11 +152,14 @@ impl RemoteWalletManager {
 | 
			
		||||
 | 
			
		||||
    /// Get a particular wallet
 | 
			
		||||
    #[allow(unreachable_patterns)]
 | 
			
		||||
    pub fn get_ledger(&self, pubkey: &Pubkey) -> Result<Arc<LedgerWallet>, RemoteWalletError> {
 | 
			
		||||
    pub fn get_ledger(
 | 
			
		||||
        &self,
 | 
			
		||||
        host_device_path: &str,
 | 
			
		||||
    ) -> Result<Arc<LedgerWallet>, RemoteWalletError> {
 | 
			
		||||
        self.devices
 | 
			
		||||
            .read()
 | 
			
		||||
            .iter()
 | 
			
		||||
            .find(|device| &device.info.pubkey == pubkey)
 | 
			
		||||
            .find(|device| device.info.host_device_path == host_device_path)
 | 
			
		||||
            .ok_or(RemoteWalletError::PubkeyNotFound)
 | 
			
		||||
            .and_then(|device| match &device.wallet_type {
 | 
			
		||||
                RemoteWalletType::Ledger(ledger) => Ok(ledger.clone()),
 | 
			
		||||
@@ -237,6 +240,8 @@ pub struct RemoteWalletInfo {
 | 
			
		||||
    pub manufacturer: String,
 | 
			
		||||
    /// RemoteWallet device serial number
 | 
			
		||||
    pub serial: String,
 | 
			
		||||
    /// RemoteWallet host device path
 | 
			
		||||
    pub host_device_path: String,
 | 
			
		||||
    /// Base pubkey of device at Solana derivation path
 | 
			
		||||
    pub pubkey: Pubkey,
 | 
			
		||||
    /// Initial read error
 | 
			
		||||
@@ -449,6 +454,7 @@ mod tests {
 | 
			
		||||
            model: "nano-s".to_string(),
 | 
			
		||||
            manufacturer: "ledger".to_string(),
 | 
			
		||||
            serial: "".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey,
 | 
			
		||||
            error: None,
 | 
			
		||||
        }));
 | 
			
		||||
@@ -465,6 +471,7 @@ mod tests {
 | 
			
		||||
            model: "nano-s".to_string(),
 | 
			
		||||
            manufacturer: "ledger".to_string(),
 | 
			
		||||
            serial: "".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey,
 | 
			
		||||
            error: None,
 | 
			
		||||
        }));
 | 
			
		||||
@@ -481,6 +488,7 @@ mod tests {
 | 
			
		||||
            model: "nano-s".to_string(),
 | 
			
		||||
            manufacturer: "ledger".to_string(),
 | 
			
		||||
            serial: "".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey,
 | 
			
		||||
            error: None,
 | 
			
		||||
        }));
 | 
			
		||||
@@ -497,6 +505,7 @@ mod tests {
 | 
			
		||||
            model: "nano-s".to_string(),
 | 
			
		||||
            manufacturer: "ledger".to_string(),
 | 
			
		||||
            serial: "".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey,
 | 
			
		||||
            error: None,
 | 
			
		||||
        }));
 | 
			
		||||
@@ -513,6 +522,7 @@ mod tests {
 | 
			
		||||
            model: "nano-s".to_string(),
 | 
			
		||||
            manufacturer: "ledger".to_string(),
 | 
			
		||||
            serial: "".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey,
 | 
			
		||||
            error: None,
 | 
			
		||||
        }));
 | 
			
		||||
@@ -531,6 +541,7 @@ mod tests {
 | 
			
		||||
            model: "nano-s".to_string(),
 | 
			
		||||
            manufacturer: "ledger".to_string(),
 | 
			
		||||
            serial: "".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey: Pubkey::default(),
 | 
			
		||||
            error: None,
 | 
			
		||||
        }));
 | 
			
		||||
@@ -547,6 +558,7 @@ mod tests {
 | 
			
		||||
            model: "".to_string(),
 | 
			
		||||
            manufacturer: "ledger".to_string(),
 | 
			
		||||
            serial: "".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey: Pubkey::default(),
 | 
			
		||||
            error: None,
 | 
			
		||||
        }));
 | 
			
		||||
@@ -581,6 +593,7 @@ mod tests {
 | 
			
		||||
            manufacturer: "Ledger".to_string(),
 | 
			
		||||
            model: "Nano S".to_string(),
 | 
			
		||||
            serial: "0001".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey,
 | 
			
		||||
            error: None,
 | 
			
		||||
        };
 | 
			
		||||
@@ -593,6 +606,8 @@ mod tests {
 | 
			
		||||
        assert!(info.matches(&test_info));
 | 
			
		||||
        test_info.model = "Nano S".to_string();
 | 
			
		||||
        assert!(info.matches(&test_info));
 | 
			
		||||
        test_info.host_device_path = "/host/device/path".to_string();
 | 
			
		||||
        assert!(info.matches(&test_info));
 | 
			
		||||
        let another_pubkey = Pubkey::new_rand();
 | 
			
		||||
        test_info.pubkey = another_pubkey;
 | 
			
		||||
        assert!(!info.matches(&test_info));
 | 
			
		||||
@@ -608,6 +623,7 @@ mod tests {
 | 
			
		||||
            model: "nano-s".to_string(),
 | 
			
		||||
            manufacturer: "ledger".to_string(),
 | 
			
		||||
            serial: "".to_string(),
 | 
			
		||||
            host_device_path: "/host/device/path".to_string(),
 | 
			
		||||
            pubkey,
 | 
			
		||||
            error: None,
 | 
			
		||||
        };
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user