soroban_cli/signer/
ledger.rs1use crate::xdr;
2
3pub use ledger_impl::*;
4
5#[derive(thiserror::Error, Debug)]
6pub enum Error {
7 #[error("Ledger Device keys are not allowed: additional-libs feature must be enabled")]
8 FeatureNotEnabled,
9
10 #[cfg(feature = "additional-libs")]
11 #[error(transparent)]
12 StellarLedger(#[from] stellar_ledger::Error),
13
14 #[error(transparent)]
15 TryFromSlice(#[from] std::array::TryFromSliceError),
16
17 #[error(transparent)]
18 Xdr(#[from] xdr::Error),
19}
20
21#[cfg(feature = "additional-libs")]
22mod ledger_impl {
23 use super::Error;
24 use crate::xdr::{DecoratedSignature, Hash, Signature, SignatureHint, Transaction};
25 use sha2::{Digest, Sha256};
26 use stellar_ledger::{Blob as _, Exchange, LedgerSigner};
27
28 #[cfg(not(feature = "emulator-tests"))]
29 pub type LedgerType = Ledger<stellar_ledger::TransportNativeHID>;
30 #[cfg(feature = "emulator-tests")]
31 pub type LedgerType = Ledger<stellar_ledger::emulator_test_support::http_transport::Emulator>;
32
33 pub struct Ledger<T: Exchange> {
34 pub(crate) index: u32,
35 pub(crate) signer: LedgerSigner<T>,
36 }
37
38 #[cfg(not(feature = "emulator-tests"))]
39 #[allow(clippy::unused_async)]
40 pub async fn new(hd_path: u32) -> Result<Ledger<stellar_ledger::TransportNativeHID>, Error> {
41 let signer = stellar_ledger::native()?;
42 Ok(Ledger {
43 index: hd_path,
44 signer,
45 })
46 }
47
48 #[cfg(feature = "emulator-tests")]
49 pub async fn new(
50 hd_path: u32,
51 ) -> Result<Ledger<stellar_ledger::emulator_test_support::http_transport::Emulator>, Error>
52 {
53 use stellar_ledger::emulator_test_support::ledger as emulator_ledger;
54 let host_port: u16 = std::env::var("SPECULOS_PORT")
56 .expect("SPECULOS_PORT env var not set")
57 .parse()
58 .expect("port must be a number");
59 let signer = emulator_ledger(host_port).await;
60
61 Ok(Ledger {
62 index: hd_path,
63 signer,
64 })
65 }
66
67 impl<T: Exchange> Ledger<T> {
68 pub async fn sign_transaction_hash(
69 &self,
70 tx_hash: &[u8; 32],
71 ) -> Result<DecoratedSignature, Error> {
72 let key = self.public_key().await?;
73 let hint = SignatureHint(key.0[28..].try_into()?);
74 let signature = Signature(
75 self.signer
76 .sign_transaction_hash(self.index, tx_hash)
77 .await?
78 .try_into()?,
79 );
80 Ok(DecoratedSignature { hint, signature })
81 }
82
83 pub async fn sign_transaction(
84 &self,
85 tx: Transaction,
86 network_passphrase: &str,
87 ) -> Result<DecoratedSignature, Error> {
88 let network_id = Hash(Sha256::digest(network_passphrase).into());
89 let signature = self
90 .signer
91 .sign_transaction(self.index, tx, network_id)
92 .await?;
93 let key = self.public_key().await?;
94 let hint = SignatureHint(key.0[28..].try_into()?);
95 let signature = Signature(signature.try_into()?);
96 Ok(DecoratedSignature { hint, signature })
97 }
98
99 pub async fn public_key(&self) -> Result<stellar_strkey::ed25519::PublicKey, Error> {
100 Ok(self.signer.get_public_key(&self.index.into()).await?)
101 }
102 }
103}
104
105#[cfg(not(feature = "additional-libs"))]
106mod ledger_impl {
107 use super::Error;
108 use crate::xdr::{DecoratedSignature, Transaction};
109 use std::marker::PhantomData;
110
111 pub type LedgerType = Ledger<GenericExchange>;
112
113 pub trait Exchange {}
114 pub struct Ledger<T: Exchange> {
115 _marker: PhantomData<T>,
116 }
117
118 #[allow(clippy::unused_async)]
119 pub async fn new(_hd_path: u32) -> Result<Ledger<GenericExchange>, Error> {
120 Err(Error::FeatureNotEnabled)
121 }
122
123 impl<T: Exchange> Ledger<T> {
124 #[allow(clippy::unused_async)]
125 pub async fn sign_transaction_hash(
126 &self,
127 _tx_hash: &[u8; 32],
128 ) -> Result<DecoratedSignature, Error> {
129 Err(Error::FeatureNotEnabled)
130 }
131
132 #[allow(clippy::unused_async)]
133 pub async fn sign_transaction(
134 &self,
135 _tx: Transaction,
136 _network_passphrase: &str,
137 ) -> Result<DecoratedSignature, Error> {
138 Err(Error::FeatureNotEnabled)
139 }
140
141 #[allow(clippy::unused_async)]
142 pub async fn public_key(&self) -> Result<stellar_strkey::ed25519::PublicKey, Error> {
143 Err(Error::FeatureNotEnabled)
144 }
145 }
146
147 pub struct GenericExchange {}
148
149 impl Exchange for GenericExchange {}
150
151 impl GenericExchange {}
152}