diff --git a/ledger_device_sdk/Cargo.toml b/ledger_device_sdk/Cargo.toml index f2db4fdd..34528aa3 100644 --- a/ledger_device_sdk/Cargo.toml +++ b/ledger_device_sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ledger_device_sdk" -version = "1.11.1" +version = "1.12.0" authors = ["yhql", "yogh333", "agrojean-ledger", "kingofpayne"] edition = "2021" license.workspace = true diff --git a/ledger_device_sdk/examples/nbgl_streaming_review.rs b/ledger_device_sdk/examples/nbgl_streaming_review.rs new file mode 100644 index 00000000..f378a410 --- /dev/null +++ b/ledger_device_sdk/examples/nbgl_streaming_review.rs @@ -0,0 +1,65 @@ +#![no_std] +#![no_main] + +// Force boot section to be embedded in +use ledger_device_sdk as _; + +use include_gif::include_gif; +use ledger_device_sdk::io::*; +use ledger_device_sdk::nbgl::{init_comm, Field, NbglGlyph, NbglStreamingReview, TransactionType}; +use ledger_secure_sdk_sys::*; + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { + exit_app(1); +} + +#[no_mangle] +extern "C" fn sample_main() { + unsafe { + nbgl_refreshReset(); + } + + let mut comm = Comm::new(); + // Initialize reference to Comm instance for NBGL + // API calls. + init_comm(&mut comm); + + // Load glyph from 64x64 4bpp gif file with include_gif macro. Creates an NBGL compatible glyph. + const FERRIS: NbglGlyph = + NbglGlyph::from_include(include_gif!("examples/crab_64x64.gif", NBGL)); + + let mut review: NbglStreamingReview = + NbglStreamingReview::new(TransactionType::Message).glyph(&FERRIS); + + review.start("Example Title", "Example Subtitle"); + + let fields = [ + Field { + name: "Name1", + value: "Value1", + }, + Field { + name: "Name2", + value: "Value2", + }, + Field { + name: "Name3", + value: "Value3", + }, + Field { + name: "Name4", + value: "Value4", + }, + Field { + name: "Name5", + value: "Value5", + }, + ]; + + for i in 0..fields.len() { + review.continue_review(&fields[i..i + 1]); + } + + review.finish("Sign to send token\n"); +} diff --git a/ledger_device_sdk/src/nbgl.rs b/ledger_device_sdk/src/nbgl.rs index 00f2a919..9a0d1225 100644 --- a/ledger_device_sdk/src/nbgl.rs +++ b/ledger_device_sdk/src/nbgl.rs @@ -80,6 +80,50 @@ impl<'a> Into for &NbglGlyph<'a> { } } +pub enum TransactionType { + Transaction, + Message, + Operation, +} + +impl From<&TransactionType> for nbgl_operationType_t { + fn from(t: &TransactionType) -> nbgl_operationType_t { + match t { + TransactionType::Transaction => TYPE_TRANSACTION.into(), + TransactionType::Message => TYPE_MESSAGE.into(), + TransactionType::Operation => TYPE_OPERATION.into(), + } + } +} + +impl TransactionType { + pub fn to_message(&self, success: bool) -> nbgl_reviewStatusType_t { + match self { + TransactionType::Transaction => { + if success { + STATUS_TYPE_TRANSACTION_SIGNED + } else { + STATUS_TYPE_TRANSACTION_REJECTED + } + } + TransactionType::Message => { + if success { + STATUS_TYPE_MESSAGE_SIGNED + } else { + STATUS_TYPE_MESSAGE_REJECTED + } + } + TransactionType::Operation => { + if success { + STATUS_TYPE_OPERATION_SIGNED + } else { + STATUS_TYPE_OPERATION_REJECTED + } + } + } + } +} + /// Initialize the global COMM_REF variable with the provided Comm instance. /// This function should be called from the main function of the application. /// The COMM_REF variable is used by the NBGL API to detect touch events and @@ -821,6 +865,116 @@ impl NbglGenericReview { } } +pub struct NbglStreamingReview { + icon: nbgl_icon_details_t, + tx_type: TransactionType, +} + +impl NbglStreamingReview { + pub fn new(tx_type: TransactionType) -> NbglStreamingReview { + NbglStreamingReview { + icon: nbgl_icon_details_t::default(), + tx_type, + } + } + + pub fn glyph(self, glyph: &NbglGlyph) -> NbglStreamingReview { + NbglStreamingReview { + icon: glyph.into(), + ..self + } + } + + pub fn start(&mut self, title: &str, subtitle: &str) -> bool { + unsafe { + let title = CString::new(title).unwrap(); + let subtitle = CString::new(subtitle).unwrap(); + + let sync_ret = ux_sync_reviewStreamingStart( + (&self.tx_type).into(), + &self.icon as *const nbgl_icon_details_t, + title.as_ptr() as *const c_char, + subtitle.as_ptr() as *const c_char, + ); + + // Return true if the user approved the transaction, false otherwise. + match sync_ret { + UX_SYNC_RET_APPROVED => { + return true; + } + _ => { + ux_sync_reviewStatus(self.tx_type.to_message(false)); + return false; + } + } + } + } + + pub fn continue_review(&mut self, fields: &[Field]) -> bool { + unsafe { + let v: Vec = fields + .iter() + .map(|f| CField { + name: CString::new(f.name).unwrap(), + value: CString::new(f.value).unwrap(), + }) + .collect(); + + // Fill the tag_value_array with the fields converted to nbgl_contentTagValue_t + let mut tag_value_array: Vec = Vec::new(); + for field in v.iter() { + let val = nbgl_contentTagValue_t { + item: field.name.as_ptr() as *const i8, + value: field.value.as_ptr() as *const i8, + ..Default::default() + }; + tag_value_array.push(val); + } + + // Create the tag_value_list with the tag_value_array. + let tag_value_list = nbgl_contentTagValueList_t { + pairs: tag_value_array.as_ptr() as *const nbgl_contentTagValue_t, + nbPairs: fields.len() as u8, + ..Default::default() + }; + + let sync_ret = ux_sync_reviewStreamingContinue( + &tag_value_list as *const nbgl_contentTagValueList_t, + ); + + // Return true if the user approved the transaction, false otherwise. + match sync_ret { + UX_SYNC_RET_APPROVED => { + return true; + } + _ => { + ux_sync_reviewStatus(self.tx_type.to_message(false)); + return false; + } + } + } + } + + pub fn finish(&mut self, finish_title: &str) -> bool { + unsafe { + let finish_title = CString::new(finish_title).unwrap(); + let sync_ret = ux_sync_reviewStreamingFinish(finish_title.as_ptr() as *const c_char); + + // Return true if the user approved the transaction, false otherwise. + match sync_ret { + ledger_secure_sdk_sys::UX_SYNC_RET_APPROVED => { + ux_sync_reviewStatus(self.tx_type.to_message(true)); + return true; + } + _ => { + ux_sync_reviewStatus(self.tx_type.to_message(false)); + return false; + } + } + } + } +} + /// A wrapper around the synchronous NBGL ux_sync_addressReview C API binding. /// Used to display address confirmation screens. pub struct NbglAddressReview<'a> {