Skip to content

Commit f52653e

Browse files
committed
Add ledger support in CLI and GUI wallet
1 parent 64b9b14 commit f52653e

File tree

40 files changed

+1184
-175
lines changed

40 files changed

+1184
-175
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,4 @@ opt-level = 2
310310
[features]
311311
trezor = []
312312
ledger = []
313-
default = ["trezor", "ledger"]
313+
default = ["trezor"]

node-gui/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ winres = "0.1"
4343

4444
[features]
4545
trezor = ["wallet-controller/trezor", "wallet-types/trezor", "wallet-cli-commands/trezor", "node-gui-backend/trezor"]
46-
default = ["trezor"]
46+
ledger = ["wallet-controller/ledger", "wallet-types/ledger", "wallet-cli-commands/ledger", "node-gui-backend/ledger"]
47+
default = ["trezor", "ledger"]

node-gui/backend/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,5 @@ rstest.workspace = true
4444

4545
[features]
4646
trezor = ["wallet/trezor", "wallet-controller/trezor", "wallet-types/trezor", "wallet-rpc-lib/trezor", "wallet-rpc-client/trezor", "wallet-cli-commands/trezor"]
47+
ledger = ["wallet/ledger", "wallet-controller/ledger", "wallet-types/ledger", "wallet-rpc-lib/ledger", "wallet-rpc-client/ledger", "wallet-cli-commands/ledger"]
48+
default = ["trezor", "ledger"]

node-gui/backend/src/backend_impl.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,44 @@ impl Backend {
351351

352352
(wallet_data, accounts_info, best_block)
353353
}
354+
#[cfg(feature = "ledger")]
355+
(WalletType::Ledger, ColdHotNodeController::Hot(controller)) => {
356+
let handles_client = WalletHandlesClient::new(
357+
controller.chainstate.clone(),
358+
controller.mempool.clone(),
359+
controller.block_prod.clone(),
360+
controller.p2p.clone(),
361+
)
362+
.await
363+
.map_err(|e| BackendError::WalletError(e.to_string()))?;
364+
365+
let (wallet_rpc, command_handler, best_block, accounts_info, accounts_data) = self
366+
.create_wallet(
367+
handles_client,
368+
file_path.clone(),
369+
wallet_args,
370+
import,
371+
wallet_events,
372+
)
373+
.await?;
374+
375+
let wallet_data = WalletData {
376+
controller: GuiHotColdController::Hot(wallet_rpc, command_handler),
377+
accounts: accounts_data,
378+
best_block,
379+
updated: false,
380+
};
381+
382+
(wallet_data, accounts_info, best_block)
383+
}
354384
#[cfg(feature = "trezor")]
355385
(WalletType::Trezor, ColdHotNodeController::Cold) => {
356386
return Err(BackendError::ColdTrezorNotSupported)
357387
}
388+
#[cfg(feature = "ledger")]
389+
(WalletType::Ledger, ColdHotNodeController::Cold) => {
390+
return Err(BackendError::ColdTrezorNotSupported)
391+
}
358392
(WalletType::Hot, ColdHotNodeController::Cold) => {
359393
return Err(BackendError::HotNotSupported)
360394
}
@@ -563,10 +597,50 @@ impl Backend {
563597

564598
(wallet_data, accounts_info, best_block, encryption_state)
565599
}
600+
#[cfg(feature = "ledger")]
601+
(WalletType::Ledger, ColdHotNodeController::Hot(controller)) => {
602+
let handles_client = WalletHandlesClient::new(
603+
controller.chainstate.clone(),
604+
controller.mempool.clone(),
605+
controller.block_prod.clone(),
606+
controller.p2p.clone(),
607+
)
608+
.await
609+
.map_err(|e| BackendError::WalletError(e.to_string()))?;
610+
611+
let (
612+
wallet_rpc,
613+
command_handler,
614+
encryption_state,
615+
best_block,
616+
accounts_info,
617+
accounts_data,
618+
) = self
619+
.open_wallet(
620+
handles_client,
621+
file_path.clone(),
622+
wallet_events,
623+
Some(HardwareWalletType::Ledger),
624+
)
625+
.await?;
626+
627+
let wallet_data = WalletData {
628+
controller: GuiHotColdController::Hot(wallet_rpc, command_handler),
629+
accounts: accounts_data,
630+
best_block,
631+
updated: false,
632+
};
633+
634+
(wallet_data, accounts_info, best_block, encryption_state)
635+
}
566636
#[cfg(feature = "trezor")]
567637
(WalletType::Trezor, ColdHotNodeController::Cold) => {
568638
return Err(BackendError::ColdTrezorNotSupported)
569639
}
640+
#[cfg(feature = "ledger")]
641+
(WalletType::Ledger, ColdHotNodeController::Cold) => {
642+
return Err(BackendError::ColdTrezorNotSupported)
643+
}
570644
(WalletType::Hot, ColdHotNodeController::Cold) => {
571645
return Err(BackendError::HotNotSupported)
572646
}

node-gui/src/main_window/main_menu.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ fn make_menu_file<'a>(wallet_mode: WalletMode) -> Item<'a, MenuMessage, Theme, i
104104
labeled_button("File", MenuMessage::NoOp),
105105
Menu::new(match wallet_mode {
106106
WalletMode::Hot => {
107-
let menu = vec![
107+
let mut menu = vec![];
108+
menu.extend([
108109
menu_item(
109110
"Create new Software wallet",
110111
MenuMessage::CreateNewWallet {
@@ -126,10 +127,9 @@ fn make_menu_file<'a>(wallet_mode: WalletMode) -> Item<'a, MenuMessage, Theme, i
126127
// TODO: enable setting when needed
127128
// menu_item("Settings", MenuMessage::NoOp),
128129
menu_item("Exit", MenuMessage::Exit),
129-
];
130+
]);
130131
#[cfg(feature = "trezor")]
131132
{
132-
let mut menu = menu;
133133
menu.insert(
134134
1,
135135
menu_item(
@@ -157,9 +157,38 @@ fn make_menu_file<'a>(wallet_mode: WalletMode) -> Item<'a, MenuMessage, Theme, i
157157
},
158158
),
159159
);
160-
menu
161160
}
162-
#[cfg(not(feature = "trezor"))]
161+
#[cfg(feature = "ledger")]
162+
{
163+
menu.insert(
164+
1,
165+
menu_item(
166+
"Create new Ledger wallet",
167+
MenuMessage::CreateNewWallet {
168+
wallet_type: WalletType::Ledger,
169+
},
170+
),
171+
);
172+
menu.insert(
173+
4,
174+
menu_item(
175+
"Recover from Ledger wallet",
176+
MenuMessage::RecoverWallet {
177+
wallet_type: WalletType::Ledger,
178+
},
179+
),
180+
);
181+
menu.insert(
182+
7,
183+
menu_item(
184+
"Open Ledger wallet",
185+
MenuMessage::OpenWallet {
186+
wallet_type: WalletType::Ledger,
187+
},
188+
),
189+
);
190+
}
191+
163192
menu
164193
}
165194
WalletMode::Cold => {

node-gui/src/main_window/main_widget/tabs/wallet/left_panel.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ pub fn view_left_panel(
122122
WalletType::Trezor => {
123123
wallet_info.best_block.1.next_height() < node_state.chain_info.best_block_height
124124
}
125+
#[cfg(feature = "ledger")]
126+
WalletType::Ledger => {
127+
wallet_info.best_block.1.next_height() < node_state.chain_info.best_block_height
128+
}
125129
WalletType::Hot => {
126130
wallet_info.best_block.1.next_height() < node_state.chain_info.best_block_height
127131
}
@@ -214,6 +218,41 @@ pub fn view_left_panel(
214218
)
215219
]
216220
}
221+
#[cfg(feature = "ledger")]
222+
WalletType::Ledger => {
223+
column![
224+
panel_button(
225+
"Transactions",
226+
SelectedPanel::Transactions,
227+
selected_panel,
228+
TRANSACTIONS_TOOLTIP_TEXT
229+
),
230+
panel_button(
231+
"Addresses",
232+
SelectedPanel::Addresses,
233+
selected_panel,
234+
ADDRESSES_TOOLTIP_TEXT
235+
),
236+
panel_button(
237+
"Send",
238+
SelectedPanel::Send,
239+
selected_panel,
240+
SEND_TOOLTIP_TEXT
241+
),
242+
panel_button(
243+
"Delegation",
244+
SelectedPanel::Delegation,
245+
selected_panel,
246+
DELEGATION_TOOLTIP_TEXT
247+
),
248+
panel_button(
249+
"Console",
250+
SelectedPanel::Console,
251+
selected_panel,
252+
CONSOLE_TOOLTIP_TEXT,
253+
)
254+
]
255+
}
217256
WalletType::Cold => {
218257
column![
219258
panel_button(

node-gui/src/main_window/main_widget/tabs/wallet/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ impl WalletTab {
180180
WalletType::Cold => SelectedPanel::Addresses,
181181
#[cfg(feature = "trezor")]
182182
WalletType::Trezor => SelectedPanel::Transactions,
183+
#[cfg(feature = "ledger")]
184+
WalletType::Ledger => SelectedPanel::Transactions,
183185
};
184186

185187
WalletTab {
@@ -488,6 +490,10 @@ impl Tab for WalletTab {
488490
WalletType::Trezor => {
489491
wallet_info.best_block.1.next_height() < node_state.chain_info.best_block_height
490492
}
493+
#[cfg(feature = "ledger")]
494+
WalletType::Ledger => {
495+
wallet_info.best_block.1.next_height() < node_state.chain_info.best_block_height
496+
}
491497
WalletType::Hot => {
492498
wallet_info.best_block.1.next_height() < node_state.chain_info.best_block_height
493499
}

node-gui/src/main_window/mod.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use wallet_cli_commands::ConsoleCommand;
3838
use wallet_controller::types::WalletTypeArgs;
3939
use wallet_types::{seed_phrase::StoreSeedPhrase, wallet_type::WalletType};
4040

41-
#[cfg(feature = "trezor")]
41+
#[cfg(any(feature = "trezor", feature = "ledger"))]
4242
use crate::widgets::create_hw_wallet::hw_wallet_create_dialog;
4343
use crate::{
4444
main_window::{main_menu::MenuMessage, main_widget::MainWidgetMessage},
@@ -148,6 +148,8 @@ pub enum WalletArgs {
148148
},
149149
#[cfg(feature = "trezor")]
150150
Trezor,
151+
#[cfg(feature = "ledger")]
152+
Ledger,
151153
}
152154

153155
impl From<&WalletArgs> for WalletType {
@@ -165,6 +167,8 @@ impl From<&WalletArgs> for WalletType {
165167
}
166168
#[cfg(feature = "trezor")]
167169
WalletArgs::Trezor => WalletType::Trezor,
170+
#[cfg(feature = "ledger")]
171+
WalletArgs::Ledger => WalletType::Ledger,
168172
}
169173
}
170174
}
@@ -291,6 +295,8 @@ impl MainWindow {
291295
},
292296
#[cfg(feature = "trezor")]
293297
WalletType::Trezor => WalletArgs::Trezor,
298+
#[cfg(feature = "ledger")]
299+
WalletType::Ledger => WalletArgs::Ledger,
294300
};
295301
self.active_dialog = ActiveDialog::WalletCreate { wallet_args };
296302
Task::none()
@@ -733,6 +739,8 @@ impl MainWindow {
733739
}
734740
#[cfg(feature = "trezor")]
735741
WalletArgs::Trezor => WalletTypeArgs::Trezor { device_id: None },
742+
#[cfg(feature = "ledger")]
743+
WalletArgs::Ledger => WalletTypeArgs::Ledger,
736744
};
737745

738746
self.file_dialog_active = true;
@@ -866,6 +874,16 @@ impl MainWindow {
866874
ImportOrCreate::Create,
867875
)
868876
.into(),
877+
#[cfg(feature = "ledger")]
878+
WalletArgs::Ledger => hw_wallet_create_dialog(
879+
Box::new(move || MainWindowMessage::ImportWalletMnemonic {
880+
args: WalletArgs::Ledger,
881+
import: ImportOrCreate::Create,
882+
}),
883+
Box::new(|| MainWindowMessage::CloseDialog),
884+
ImportOrCreate::Create,
885+
)
886+
.into(),
869887
},
870888
ActiveDialog::WalletRecover { wallet_type } => {
871889
let is_cold = *wallet_type == WalletType::Cold;
@@ -890,6 +908,16 @@ impl MainWindow {
890908
ImportOrCreate::Import,
891909
)
892910
.into(),
911+
#[cfg(feature = "ledger")]
912+
WalletType::Ledger => hw_wallet_create_dialog(
913+
Box::new(move || MainWindowMessage::ImportWalletMnemonic {
914+
args: WalletArgs::Ledger,
915+
import: ImportOrCreate::Create,
916+
}),
917+
Box::new(|| MainWindowMessage::CloseDialog),
918+
ImportOrCreate::Import,
919+
)
920+
.into(),
893921
}
894922
}
895923

wallet/src/key_chain/master_key_chain/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use crypto::key::hdkd::u31::U31;
2121
use crypto::vrf::ExtendedVRFPrivateKey;
2222
use std::sync::Arc;
2323
use wallet_storage::{
24-
StoreTxRwUnlocked, WalletStorageReadLocked, WalletStorageReadUnlocked,
25-
WalletStorageWriteLocked, WalletStorageWriteUnlocked,
24+
WalletStorageReadLocked, WalletStorageReadUnlocked, WalletStorageWriteLocked,
25+
WalletStorageWriteUnlocked,
2626
};
2727
use wallet_types::seed_phrase::{SerializableSeedPhrase, StoreSeedPhrase};
2828

@@ -59,9 +59,9 @@ impl MasterKeyChain {
5959
))
6060
}
6161

62-
pub fn new_from_mnemonic<B: storage::Backend>(
62+
pub fn new_from_mnemonic(
6363
chain_config: Arc<ChainConfig>,
64-
db_tx: &mut StoreTxRwUnlocked<B>,
64+
db_tx: &mut impl WalletStorageWriteUnlocked,
6565
mnemonic_str: &str,
6666
passphrase: Option<&str>,
6767
save_seed_phrase: StoreSeedPhrase,
@@ -80,9 +80,9 @@ impl MasterKeyChain {
8080
)
8181
}
8282

83-
fn new_from_root_key<B: storage::Backend>(
83+
fn new_from_root_key(
8484
chain_config: Arc<ChainConfig>,
85-
db_tx: &mut StoreTxRwUnlocked<B>,
85+
db_tx: &mut impl WalletStorageWriteUnlocked,
8686
root_key: ExtendedPrivateKey,
8787
root_vrf_key: ExtendedVRFPrivateKey,
8888
seed_phrase: Option<SerializableSeedPhrase>,

wallet/src/signer/ledger_signer/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,9 +1152,8 @@ impl LedgerSignerProvider {
11521152
pub async fn load_from_database(
11531153
chain_config: Arc<ChainConfig>,
11541154
db_tx: &(impl WalletStorageReadLocked + Sync),
1155-
_device_id: Option<String>,
1155+
//_device_id: Option<String>,
11561156
) -> WalletResult<Self> {
1157-
//let (client, data) = find_trezor_device_from_db(db_tx, device_id)?;
11581157
let (mut client, data) = find_ledger_device().await?;
11591158

11601159
check_public_keys_against_db(db_tx, &mut client, chain_config).await?;

0 commit comments

Comments
 (0)