diff --git a/Justfile b/Justfile index 932395b..173d044 100644 --- a/Justfile +++ b/Justfile @@ -1,3 +1,5 @@ +import? 'local.just' + cleanup: #!/usr/bin/env bash sudo rm -rf target @@ -8,6 +10,12 @@ cleanup: exit 3; fi +fmt: + cargo fmt --all + +unit_tests: + RUSTFLAGS='-D warnings' bash local_unit_tests.sh + build_all: #!/usr/bin/env bash bash local_test_helper.sh -c build_all @@ -25,6 +33,14 @@ pull_dev_images: docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest +run_builder: + # docker command to build + docker run --rm -ti --privileged -v "/dev/bus/usb:/dev/bus/usb" -v "$(realpath ./):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest + +run_builder_with_local_sdk: + # docker command to build with local sdk folder (relative path via volume) + docker run --rm -ti --privileged -v "/dev/bus/usb:/dev/bus/usb" -v "$(realpath ./):/app" -v "$(realpath ../ledger-device-rust-sdk):/sdk" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest + run_speculos_nanos: docker run --rm -p 5000:5000 -p 5001:5001 -v '/dev/bus/usb:/dev/bus/usb' \ -v "$(realpath ./):/app" -it --name \ diff --git a/near_gas/src/lib.rs b/near_gas/src/lib.rs index 811c466..8842c0f 100644 --- a/near_gas/src/lib.rs +++ b/near_gas/src/lib.rs @@ -9,6 +9,9 @@ use numtoa::NumToA; #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] pub struct NearGas(u64); +/// A buffer, large enough to fit all [NearGas] representation values into +pub type GasBuffer = Buffer<30>; + /// Gas is a type for storing amount of gas. type Gas = u64; @@ -68,7 +71,7 @@ impl NearGas { self.0 } - pub fn display_as_buffer(&self, result: &mut Buffer<30>) { + pub fn display_as_buffer(&self, result: &mut GasBuffer) { if *self == NearGas::from_gas(0) { result.write_str("0 Tgas"); } else if *self < NearGas::from_ggas(1) { @@ -115,8 +118,7 @@ impl BorshDeserialize for NearGas { #[cfg(test)] mod test { - use crate::NearGas; - use fmt_buffer::Buffer; + use crate::{GasBuffer, NearGas}; #[test] fn test_display() { @@ -146,7 +148,7 @@ mod test { "1000000.5 Tgas", ), ] { - let mut buffer: Buffer<30> = Buffer::new(); + let mut buffer: GasBuffer = GasBuffer::new(); near_gas.display_as_buffer(&mut buffer); assert_eq!(buffer.as_str(), expected_display); diff --git a/near_token/src/lib.rs b/near_token/src/lib.rs index 48efd29..bbbf114 100644 --- a/near_token/src/lib.rs +++ b/near_token/src/lib.rs @@ -11,6 +11,9 @@ type Balance = u128; const ONE_MILLINEAR: u128 = 10_u128.pow(21); use numtoa::NumToA; +/// A buffer, large enough to fit all [NearToken] representation values into +pub type TokenBuffer = Buffer<30>; + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct NearToken(pub Balance); @@ -45,7 +48,7 @@ impl NearToken { self.0 } - pub fn display_as_buffer(&self, result: &mut Buffer<30>) { + pub fn display_as_buffer(&self, result: &mut TokenBuffer) { if *self == NearToken::from_yoctonear(0) { result.write_str("0 NEAR"); } else if *self == NearToken::from_yoctonear(1) { @@ -96,8 +99,9 @@ impl BorshDeserialize for NearToken { } #[cfg(test)] mod tests { + use crate::TokenBuffer; + use super::NearToken; - use fmt_buffer::Buffer; #[test] fn test_display() { @@ -107,7 +111,7 @@ mod tests { (0, "0 NEAR"), (1, "1 yoctoNEAR"), ] { - let mut buffer: Buffer<30> = Buffer::new(); + let mut buffer: TokenBuffer = TokenBuffer::new(); let token = NearToken::from_yoctonear(integer); @@ -127,7 +131,7 @@ mod tests { (1100, "1.10 NEAR"), (1000 * 1_000_000, "1000000.00 NEAR"), ] { - let mut buffer: Buffer<30> = Buffer::new(); + let mut buffer: TokenBuffer = TokenBuffer::new(); let token = NearToken::from_millinear(integer_millis); diff --git a/src/app_ui/aliases.rs b/src/app_ui/aliases.rs new file mode 100644 index 0000000..e2b1c58 --- /dev/null +++ b/src/app_ui/aliases.rs @@ -0,0 +1,60 @@ +use fmt_buffer::Buffer; + +use crate::utils::types::{capped_string::CappedString, hex_display::HexDisplay}; + +/// A capped string for storing +/// https://docs.rs/near-account-id/1.0.0/near_account_id/struct.AccountId.html +/// where all bytes after 64-byte prefix are truncated and displayed as `... N bytes` ellipsis +/// +/// 64 is enough to show implicit account ID-s and most of +/// practical named account ID-s +pub type CappedAccountId = CappedString<64>; + +/// A buffer, large enough to contain string representation +/// of u64 +pub type U64Buffer = [u8; 20]; +/// A buffer, large enough to contain string representation +/// of u32 +pub type U32Buffer = [u8; 10]; + +/// Type, which is used for displaying full `args` field of +/// https://docs.rs/near-primitives/0.21.2/near_primitives/action/struct.FunctionCallAction.html +/// or prefix of `args` with suffix truncated and displayed as `... N bytes` ellipsis, +/// displayed in hexadecimal form, when `args` are considered just arbitrary bytes. +/// +/// Current parameter value is limited by `nanos` capabilities. +/// The parameter value can be made larger with `#[cfg(target_os = "...")]` +/// for other platforms +/// see https://github.com/dj8yfo/app-near-rs/pull/45/files +pub type FnCallHexDisplay = HexDisplay<200>; + +/// Type, which is used for displaying full `args` field of +/// https://docs.rs/near-primitives/0.21.2/near_primitives/action/struct.FunctionCallAction.html +/// or prefix of `args` with suffix truncated and displayed as `... N bytes` ellipsis, +/// displayed as string, when `args` is considered to be a valid utf-8 string +/// +/// Current parameter value is limited by `nanos` capabilities. +/// The parameter value can be made larger with `#[cfg(target_os = "...")]` +/// for other platforms +/// see https://github.com/dj8yfo/app-near-rs/pull/45/files +pub type FnCallCappedString = CappedString<200>; + +/// Type, which is used for displaying full `method_names` field of +/// https://docs.rs/near-primitives/0.21.2/near_primitives/account/struct.FunctionCallPermission.html +/// or prefix of `method_names` with suffix truncated and displayed as `... N bytes` ellipsis +/// +/// Current parameter value is limited by `nanos` capabilities. +/// The parameter value can be made larger with `#[cfg(target_os = "...")]` +/// for other platforms +/// see https://github.com/dj8yfo/app-near-rs/pull/45/files +pub type MethodNamesBuffer = Buffer<210>; + +/// Type, which is used for displaying full `message` field of +/// https://docs.rs/near-ledger/0.5.0/near_ledger/struct.NEP413Payload.html +/// or prefix of `message` with suffix truncated and displayed as `... N bytes` ellipsis +/// +/// Current parameter value is limited by `nanos` capabilities. +/// The parameter value can be made larger with `#[cfg(target_os = "...")]` +/// for other platforms +/// see https://github.com/dj8yfo/app-near-rs/pull/45/files +pub type NEP413CappedString = CappedString<400>; diff --git a/src/app_ui/sign/common/action/add_key_common.rs b/src/app_ui/sign/common/action/add_key_common.rs index ddd7016..0ae2038 100644 --- a/src/app_ui/sign/common/action/add_key_common.rs +++ b/src/app_ui/sign/common/action/add_key_common.rs @@ -1,3 +1,4 @@ +use crate::app_ui::aliases::U64Buffer; use crate::{ app_ui::fields_writer::FieldsWriter, parsing, sign_ui::common::tx_public_key_context, utils::types::elipsis_fields::ElipsisFields, @@ -7,14 +8,14 @@ use ledger_device_sdk::ui::gadgets::Field; use numtoa::NumToA; pub struct FieldsContext { - pub num_buf: [u8; 20], + pub num_buf: U64Buffer, pub pub_key_context: tx_public_key_context::FieldsContext, } impl FieldsContext { pub fn new() -> Self { Self { - num_buf: [0u8; 20], + num_buf: U64Buffer::default(), pub_key_context: tx_public_key_context::FieldsContext::new(), } } @@ -36,7 +37,7 @@ pub fn format<'b, 'a: 'b, const N: usize>( writer.push_fields(ElipsisFields::one(Field { name: "Public Key", - value: field_context.pub_key_context.buffer.as_str(), + value: field_context.pub_key_context.as_str(), })); writer.push_fields(ElipsisFields::one(Field { diff --git a/src/app_ui/sign/common/action/create_account.rs b/src/app_ui/sign/common/action/create_account.rs index ea57969..4005863 100644 --- a/src/app_ui/sign/common/action/create_account.rs +++ b/src/app_ui/sign/common/action/create_account.rs @@ -3,9 +3,11 @@ use ledger_device_sdk::ui::gadgets::Field; use crate::app_ui::fields_writer::FieldsWriter; +/// action type (1) +const MAX_FIELDS: usize = 1; pub fn format( _create_account: &parsing::types::CreateAccount, - writer: &'_ mut FieldsWriter<'_, 1>, + writer: &'_ mut FieldsWriter<'_, MAX_FIELDS>, ) { writer.push_fields(ElipsisFields::one(Field { name: "Action type", diff --git a/src/app_ui/sign/common/action/delete_account.rs b/src/app_ui/sign/common/action/delete_account.rs index 9041248..ca5879d 100644 --- a/src/app_ui/sign/common/action/delete_account.rs +++ b/src/app_ui/sign/common/action/delete_account.rs @@ -1,23 +1,29 @@ -use crate::{parsing, utils::types::elipsis_fields::ElipsisFields}; +use crate::{ + parsing, + utils::types::elipsis_fields::{ElipsisFields, EllipsisBuffer}, +}; use ledger_device_sdk::ui::gadgets::Field; use crate::app_ui::fields_writer::FieldsWriter; +/// action type (1) + Beneficiary `EllipsisFields` (1-2) +const MAX_FIELDS: usize = 3; + pub struct FieldsContext { - pub beneficiary_display_buf: [u8; 20], + pub beneficiary_display_buf: EllipsisBuffer, } impl FieldsContext { pub fn new() -> Self { Self { - beneficiary_display_buf: [0u8; 20], + beneficiary_display_buf: EllipsisBuffer::default(), } } } pub fn format<'b, 'a: 'b>( delete_account: &'a mut parsing::types::DeleteAccount, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 3>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { writer.push_fields(ElipsisFields::one(Field { name: "Action type", diff --git a/src/app_ui/sign/common/action/delete_key.rs b/src/app_ui/sign/common/action/delete_key.rs index 85dd3fc..bd15eb1 100644 --- a/src/app_ui/sign/common/action/delete_key.rs +++ b/src/app_ui/sign/common/action/delete_key.rs @@ -5,10 +5,13 @@ use crate::{ utils::types::elipsis_fields::ElipsisFields, }; +/// action type(1) + Public Key (1) +const MAX_FIELDS: usize = 2; + pub fn format<'b, 'a: 'b>( delete_key: &parsing::types::DeleteKey, field_context: &'a mut tx_public_key_context::FieldsContext, - writer: &'_ mut FieldsWriter<'b, 2>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { field_context.format_public_key(&delete_key.public_key); writer.push_fields(ElipsisFields::one(Field { @@ -18,6 +21,6 @@ pub fn format<'b, 'a: 'b>( writer.push_fields(ElipsisFields::one(Field { name: "Public Key", - value: field_context.buffer.as_str(), + value: field_context.as_str(), })); } diff --git a/src/app_ui/sign/common/action/deploy_contract.rs b/src/app_ui/sign/common/action/deploy_contract.rs index 2ae6644..976016e 100644 --- a/src/app_ui/sign/common/action/deploy_contract.rs +++ b/src/app_ui/sign/common/action/deploy_contract.rs @@ -3,9 +3,12 @@ use ledger_device_sdk::ui::gadgets::Field; use crate::app_ui::fields_writer::FieldsWriter; +/// action type (1) + Contract SHA256 (1) +const MAX_FIELDS: usize = 2; + pub fn format<'b>( deploy_contract: &'b parsing::types::DeployContract, - writer: &'_ mut FieldsWriter<'b, 2>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { writer.push_fields(ElipsisFields::one(Field { name: "Action type", diff --git a/src/app_ui/sign/common/action/function_call_bin.rs b/src/app_ui/sign/common/action/function_call_bin.rs index 8c6b508..5e5c730 100644 --- a/src/app_ui/sign/common/action/function_call_bin.rs +++ b/src/app_ui/sign/common/action/function_call_bin.rs @@ -1,22 +1,27 @@ +use crate::app_ui::aliases::FnCallHexDisplay; use crate::app_ui::fields_writer::FieldsWriter; -use crate::utils::types::elipsis_fields::ElipsisFields; -use crate::utils::types::hex_display::HexDisplay; +use crate::utils::types::elipsis_fields::{ElipsisFields, EllipsisBuffer}; pub struct FieldsContext { - pub args_display_buf: [u8; 20], + pub args_display_buf: EllipsisBuffer, } impl FieldsContext { pub fn new() -> Self { Self { - args_display_buf: [0u8; 20], + args_display_buf: EllipsisBuffer::default(), } } } + +/// action type (1) + Method Name `ElipsisFields` (1-2) + +/// Gas (1) + Deposit (1) + Args Binary `ElipsisFields` (1-2) +const MAX_FIELDS: usize = 7; + pub fn format<'b, 'a: 'b>( - args: &'b HexDisplay<200>, + args: &'b FnCallHexDisplay, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 7>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { let args_fields = ElipsisFields::from_hex_display(args, "Args Binary", &mut field_context.args_display_buf); diff --git a/src/app_ui/sign/common/action/function_call_common.rs b/src/app_ui/sign/common/action/function_call_common.rs index 240b59c..24362e8 100644 --- a/src/app_ui/sign/common/action/function_call_common.rs +++ b/src/app_ui/sign/common/action/function_call_common.rs @@ -1,24 +1,25 @@ use crate::{ - parsing::{self}, - utils::types::elipsis_fields::ElipsisFields, + parsing, + utils::types::elipsis_fields::{ElipsisFields, EllipsisBuffer}, }; -use fmt_buffer::Buffer; use ledger_device_sdk::ui::gadgets::Field; +use near_gas::GasBuffer; +use near_token::TokenBuffer; use crate::app_ui::fields_writer::FieldsWriter; pub struct FieldsContext { - pub method_name_display_buf: [u8; 20], - pub gas_buf: Buffer<30>, - pub deposit_buffer: Buffer<30>, + pub method_name_display_buf: EllipsisBuffer, + pub gas_buf: GasBuffer, + pub deposit_buffer: TokenBuffer, } impl FieldsContext { pub fn new() -> Self { Self { - method_name_display_buf: [0u8; 20], - gas_buf: Buffer::new(), - deposit_buffer: Buffer::new(), + method_name_display_buf: EllipsisBuffer::default(), + gas_buf: GasBuffer::new(), + deposit_buffer: TokenBuffer::new(), } } } diff --git a/src/app_ui/sign/common/action/function_call_permission.rs b/src/app_ui/sign/common/action/function_call_permission.rs index d006bd4..f8f7dd3 100644 --- a/src/app_ui/sign/common/action/function_call_permission.rs +++ b/src/app_ui/sign/common/action/function_call_permission.rs @@ -1,33 +1,41 @@ +use crate::app_ui::aliases::U32Buffer; use crate::{ - app_ui::fields_writer::FieldsWriter, parsing, utils::types::elipsis_fields::ElipsisFields, + app_ui::fields_writer::FieldsWriter, + parsing, + utils::types::elipsis_fields::{ElipsisFields, EllipsisBuffer}, }; -use fmt_buffer::Buffer; - use ledger_device_sdk::ui::gadgets::Field; +use near_token::TokenBuffer; use numtoa::NumToA; pub struct FieldsContext { - pub num_buf: [u8; 10], - pub receiver_display_buf: [u8; 20], - pub method_names_display_buf: [u8; 20], - pub allowance_buffer: Buffer<30>, + pub num_buf: U32Buffer, + pub receiver_display_buf: EllipsisBuffer, + pub method_names_display_buf: EllipsisBuffer, + pub allowance_buffer: TokenBuffer, } impl FieldsContext { pub fn new() -> Self { Self { - num_buf: [0u8; 10], - receiver_display_buf: [0u8; 20], - method_names_display_buf: [0u8; 20], - allowance_buffer: Buffer::new(), + num_buf: U32Buffer::default(), + receiver_display_buf: EllipsisBuffer::default(), + method_names_display_buf: EllipsisBuffer::default(), + allowance_buffer: TokenBuffer::new(), } } } +/// action type (1) + Public Key (1) + Access Key Nonce (1) + +/// Access Permission (1) + FnCall Allowance (1) + +/// FnCall Receiver `ElipsisFields` (1-2) + Total FnCall Methods (1) + +/// Method Names `ElipsisFields` (1-2) +const MAX_FIELDS: usize = 10; + pub fn format<'b, 'a: 'b>( function_call_perm: &'a mut parsing::types::FunctionCallPermission, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 10>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { let allowance = match function_call_perm.allowance { Some(allowance) => { diff --git a/src/app_ui/sign/common/action/function_call_str.rs b/src/app_ui/sign/common/action/function_call_str.rs index 667d6dd..059d4dc 100644 --- a/src/app_ui/sign/common/action/function_call_str.rs +++ b/src/app_ui/sign/common/action/function_call_str.rs @@ -1,23 +1,28 @@ -use crate::utils::types::capped_string::CappedString; +use crate::app_ui::aliases::FnCallCappedString; use crate::app_ui::fields_writer::FieldsWriter; -use crate::utils::types::elipsis_fields::ElipsisFields; +use crate::utils::types::elipsis_fields::{ElipsisFields, EllipsisBuffer}; pub struct FieldsContext { - pub args_display_buf: [u8; 20], + pub args_display_buf: EllipsisBuffer, } impl FieldsContext { pub fn new() -> Self { Self { - args_display_buf: [0u8; 20], + args_display_buf: EllipsisBuffer::default(), } } } + +/// action type (1) + Method Name `ElipsisFields` (1-2) + +/// Gas (1) + Deposit (1) + Args String `ElipsisFields` (1-2) +const MAX_FIELDS: usize = 7; + pub fn format<'b, 'a: 'b>( - args: &'b mut CappedString<200>, + args: &'b mut FnCallCappedString, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 7>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { let args_fields = ElipsisFields::from_capped_string(args, "Args String", &mut field_context.args_display_buf); diff --git a/src/app_ui/sign/common/action/mod.rs b/src/app_ui/sign/common/action/mod.rs index 7871023..1db387c 100644 --- a/src/app_ui/sign/common/action/mod.rs +++ b/src/app_ui/sign/common/action/mod.rs @@ -1,9 +1,5 @@ -use crate::{ - app_ui::fields_writer::FieldsWriter, - handlers::common::action::ActionParams, - parsing, - utils::types::{capped_string::CappedString, hex_display::HexDisplay}, -}; +use crate::app_ui::aliases::{FnCallCappedString, FnCallHexDisplay, U32Buffer}; +use crate::{app_ui::fields_writer::FieldsWriter, handlers::common::action::ActionParams, parsing}; use fmt_buffer::Buffer; use ledger_device_sdk::ui::{ @@ -28,7 +24,7 @@ mod transfer; pub fn ui_display_transfer(transfer: &parsing::types::Transfer, params: ActionParams) -> bool { let mut field_context: transfer::FieldsContext = transfer::FieldsContext::new(); - let mut writer: FieldsWriter<'_, 2> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); transfer::format(transfer, &mut field_context, &mut writer); @@ -39,7 +35,7 @@ pub fn ui_display_create_account( create_account: &parsing::types::CreateAccount, params: ActionParams, ) -> bool { - let mut writer: FieldsWriter<'_, 1> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); create_account::format(create_account, &mut writer); @@ -50,7 +46,7 @@ pub fn ui_display_delete_account( delete_account: &mut parsing::types::DeleteAccount, params: ActionParams, ) -> bool { - let mut writer: FieldsWriter<'_, 3> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); let mut field_context: delete_account::FieldsContext = delete_account::FieldsContext::new(); delete_account::format(delete_account, &mut field_context, &mut writer); @@ -61,7 +57,7 @@ pub fn ui_display_delete_account( pub fn ui_display_delete_key(delete_key: &parsing::types::DeleteKey, params: ActionParams) -> bool { let mut field_context: tx_public_key_context::FieldsContext = tx_public_key_context::FieldsContext::new(); - let mut writer: FieldsWriter<'_, 2> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); delete_key::format(delete_key, &mut field_context, &mut writer); @@ -70,19 +66,23 @@ pub fn ui_display_delete_key(delete_key: &parsing::types::DeleteKey, params: Act pub fn ui_display_stake(stake: &parsing::types::Stake, params: ActionParams) -> bool { let mut field_context: stake::FieldsContext = stake::FieldsContext::new(); - let mut writer: FieldsWriter<'_, 3> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); stake::format(stake, &mut field_context, &mut writer); ui_display_common(&mut writer, params) } +/// action type (1) + Public Key (1) + Access Key Nonce (1) + +/// Access Permission (1) +const ADD_KEY_FULL_ACCESS_MAX_FIELDS: usize = 4; + pub fn ui_display_add_key_fullaccess( add_key: &parsing::types::AddKey, params: ActionParams, ) -> bool { let mut field_context: add_key_common::FieldsContext = add_key_common::FieldsContext::new(); - let mut writer: FieldsWriter<'_, 4> = FieldsWriter::new(); + let mut writer: FieldsWriter<'_, ADD_KEY_FULL_ACCESS_MAX_FIELDS> = FieldsWriter::new(); add_key_common::format(add_key, &mut field_context, &mut writer, "Full Access"); @@ -98,7 +98,7 @@ pub fn ui_display_add_key_functioncall( add_key_common::FieldsContext::new(); let mut func_call_field_context: function_call_permission::FieldsContext = function_call_permission::FieldsContext::new(); - let mut writer: FieldsWriter<'_, 10> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); add_key_common::format( add_key, @@ -115,7 +115,7 @@ pub fn ui_display_deploy_contract( deploy_contract: &parsing::types::DeployContract, params: ActionParams, ) -> bool { - let mut writer: FieldsWriter<'_, 2> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); deploy_contract::format(deploy_contract, &mut writer); @@ -124,10 +124,10 @@ pub fn ui_display_deploy_contract( pub fn ui_display_function_call_str( func_call_common: &mut parsing::types::FunctionCallCommon, - args: &mut CappedString<200>, + args: &mut FnCallCappedString, params: ActionParams, ) -> bool { - let mut writer: FieldsWriter<'_, 7> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); let mut common_field_context: function_call_common::FieldsContext = function_call_common::FieldsContext::new(); @@ -141,10 +141,10 @@ pub fn ui_display_function_call_str( pub fn ui_display_function_call_bin( func_call_common: &mut parsing::types::FunctionCallCommon, - args: &HexDisplay<200>, + args: &FnCallHexDisplay, params: ActionParams, ) -> bool { - let mut writer: FieldsWriter<'_, 7> = FieldsWriter::new(); + let mut writer = FieldsWriter::new(); let mut common_field_context: function_call_common::FieldsContext = function_call_common::FieldsContext::new(); @@ -159,7 +159,7 @@ pub fn ui_display_common( writer: &mut FieldsWriter<'_, N>, params: ActionParams, ) -> bool { - let mut ordinal_fmt_buf = Buffer::<25>::new(); + let mut ordinal_fmt_buf = OrdinalStringBuffer::new(); let is_last = ordinal_string(&mut ordinal_fmt_buf, params); let ordinal_str = ordinal_fmt_buf.as_str(); @@ -190,8 +190,12 @@ pub fn ui_display_common( my_review.show() } -fn ordinal_string(fmt_buf: &mut Buffer<25>, params: ActionParams) -> bool { - let mut num_out = [0u8; 10]; +/// a buffer, large enough to fit description string and +/// 2 u32 numbers as strings +type OrdinalStringBuffer = Buffer<40>; + +fn ordinal_string(fmt_buf: &mut OrdinalStringBuffer, params: ActionParams) -> bool { + let mut num_out = U32Buffer::default(); let header = if params.is_nested_delegate { "View subaction " } else { diff --git a/src/app_ui/sign/common/action/stake.rs b/src/app_ui/sign/common/action/stake.rs index 1a8b138..8fe02f2 100644 --- a/src/app_ui/sign/common/action/stake.rs +++ b/src/app_ui/sign/common/action/stake.rs @@ -3,29 +3,31 @@ use crate::{ sign_ui::common::tx_public_key_context, utils::types::elipsis_fields::ElipsisFields, }; -use fmt_buffer::Buffer; use ledger_device_sdk::ui::gadgets::Field; +use near_token::TokenBuffer; use crate::app_ui::fields_writer::FieldsWriter; pub struct FieldsContext { - pub stake_buffer: Buffer<30>, + pub stake_buffer: TokenBuffer, pub pub_key_context: tx_public_key_context::FieldsContext, } impl FieldsContext { pub fn new() -> Self { Self { - stake_buffer: Buffer::new(), + stake_buffer: TokenBuffer::new(), pub_key_context: tx_public_key_context::FieldsContext::new(), } } } +/// action type (1) + Stake (1) + Public Key (1) +const MAX_FIELDS: usize = 3; pub fn format<'b, 'a: 'b>( stake: &parsing::types::Stake, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 3>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { field_context .pub_key_context @@ -45,6 +47,6 @@ pub fn format<'b, 'a: 'b>( writer.push_fields(ElipsisFields::one(Field { name: "Public Key", - value: field_context.pub_key_context.buffer.as_str(), + value: field_context.pub_key_context.as_str(), })); } diff --git a/src/app_ui/sign/common/action/transfer.rs b/src/app_ui/sign/common/action/transfer.rs index 1191956..6852718 100644 --- a/src/app_ui/sign/common/action/transfer.rs +++ b/src/app_ui/sign/common/action/transfer.rs @@ -2,27 +2,30 @@ use crate::{ parsing::{self}, utils::types::elipsis_fields::ElipsisFields, }; -use fmt_buffer::Buffer; use ledger_device_sdk::ui::gadgets::Field; +use near_token::TokenBuffer; use crate::app_ui::fields_writer::FieldsWriter; pub struct FieldsContext { - pub amount_buffer: Buffer<30>, + pub amount_buffer: TokenBuffer, } impl FieldsContext { pub fn new() -> Self { Self { - amount_buffer: Buffer::new(), + amount_buffer: TokenBuffer::new(), } } } +/// action type (1) + Amount (1) +const MAX_FIELDS: usize = 2; + pub fn format<'b, 'a: 'b>( transfer: &parsing::types::Transfer, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 2>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { writer.push_fields(ElipsisFields::one(Field { name: "Action type", diff --git a/src/app_ui/sign/common/tx_public_key_context.rs b/src/app_ui/sign/common/tx_public_key_context.rs index 1cd6d54..02791ad 100644 --- a/src/app_ui/sign/common/tx_public_key_context.rs +++ b/src/app_ui/sign/common/tx_public_key_context.rs @@ -2,7 +2,8 @@ use crate::{parsing::types::TxPublicKey, utils::types::base58_buf::Base58Buf}; use fmt_buffer::Buffer; pub struct FieldsContext { - pub buffer: Buffer<100>, + /// large enough buffer to fit `key_type:` prefix and key base 58 representation + buffer: Buffer<100>, } impl FieldsContext { @@ -35,4 +36,8 @@ impl FieldsContext { } } } + + pub fn as_str(&mut self) -> &str { + self.buffer.as_str() + } } diff --git a/src/app_ui/sign/nep366_delegate_action/prefix.rs b/src/app_ui/sign/nep366_delegate_action/prefix.rs index 4c0f127..1eb2c69 100644 --- a/src/app_ui/sign/nep366_delegate_action/prefix.rs +++ b/src/app_ui/sign/nep366_delegate_action/prefix.rs @@ -5,29 +5,35 @@ use ledger_device_sdk::ui::{ use numtoa::NumToA; use crate::{ - app_ui::fields_writer::FieldsWriter, parsing, utils::types::elipsis_fields::ElipsisFields, + app_ui::{aliases::U32Buffer, fields_writer::FieldsWriter}, + parsing, + utils::types::elipsis_fields::{ElipsisFields, EllipsisBuffer}, }; struct FieldsContext { - display_buf1: [u8; 20], - display_buf2: [u8; 20], - numtoa_buf: [u8; 10], + display_buf1: EllipsisBuffer, + display_buf2: EllipsisBuffer, + numtoa_buf: U32Buffer, } impl FieldsContext { pub fn new() -> Self { Self { - display_buf1: [0u8; 20], - display_buf2: [0u8; 20], - numtoa_buf: [0u8; 10], + display_buf1: EllipsisBuffer::default(), + display_buf2: EllipsisBuffer::default(), + numtoa_buf: U32Buffer::default(), } } } +/// Sender Id `ElipsisFields` (1-2) + Receiver Id `ElipsisFields` (1-2) + +/// Total subactions (1) +const MAX_FIELDS: usize = 5; + fn format<'b, 'a: 'b>( prefix: &'b mut parsing::types::nep366_delegate_action::prefix::Prefix, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 5>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { let sender_id = ElipsisFields::from_capped_string( &mut prefix.sender_id, @@ -53,7 +59,7 @@ fn format<'b, 'a: 'b>( })); } pub fn ui_display(prefix: &mut parsing::types::nep366_delegate_action::prefix::Prefix) -> bool { - let mut field_writer: FieldsWriter<'_, 5> = FieldsWriter::new(); + let mut field_writer = FieldsWriter::new(); let mut field_context: FieldsContext = FieldsContext::new(); format(prefix, &mut field_context, &mut field_writer); diff --git a/src/app_ui/sign/nep366_delegate_action/suffix.rs b/src/app_ui/sign/nep366_delegate_action/suffix.rs index 30334e3..28bfd09 100644 --- a/src/app_ui/sign/nep366_delegate_action/suffix.rs +++ b/src/app_ui/sign/nep366_delegate_action/suffix.rs @@ -5,30 +5,35 @@ use ledger_device_sdk::ui::{ use numtoa::NumToA; use crate::{ - app_ui::fields_writer::FieldsWriter, parsing, sign_ui::common::tx_public_key_context, + app_ui::{aliases::U64Buffer, fields_writer::FieldsWriter}, + parsing, + sign_ui::common::tx_public_key_context, utils::types::elipsis_fields::ElipsisFields, }; struct FieldsContext { - pub num_buf1: [u8; 20], - pub num_buf2: [u8; 20], + pub num_buf1: U64Buffer, + pub num_buf2: U64Buffer, pub pub_key_context: tx_public_key_context::FieldsContext, } impl FieldsContext { pub fn new() -> Self { Self { - num_buf1: [0u8; 20], - num_buf2: [0u8; 20], + num_buf1: U64Buffer::default(), + num_buf2: U64Buffer::default(), pub_key_context: tx_public_key_context::FieldsContext::new(), } } } +/// Nonce (1) + Max Block Height (1) + Public Key (1) +const MAX_FIELDS: usize = 3; + fn format<'b, 'a: 'b>( suffix: &'b parsing::types::nep366_delegate_action::suffix::Suffix, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 3>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { writer.push_fields(ElipsisFields::one(Field { name: "Nonce", @@ -49,12 +54,12 @@ fn format<'b, 'a: 'b>( .format_public_key(&suffix.public_key); writer.push_fields(ElipsisFields::one(Field { name: "Public Key", - value: field_context.pub_key_context.buffer.as_str(), + value: field_context.pub_key_context.as_str(), })); } pub fn ui_display(suffix: &parsing::types::nep366_delegate_action::suffix::Suffix) -> bool { - let mut field_writer: FieldsWriter<'_, 3> = FieldsWriter::new(); + let mut field_writer = FieldsWriter::new(); let mut field_context: FieldsContext = FieldsContext::new(); format(suffix, &mut field_context, &mut field_writer); diff --git a/src/app_ui/sign/nep413/payload.rs b/src/app_ui/sign/nep413/payload.rs index d0f6c8c..210d14a 100644 --- a/src/app_ui/sign/nep413/payload.rs +++ b/src/app_ui/sign/nep413/payload.rs @@ -4,34 +4,43 @@ use ledger_device_sdk::ui::{ }; use crate::{ - app_ui::fields_writer::FieldsWriter, parsing::types::nep413::payload::Payload, - utils::types::elipsis_fields::ElipsisFields, + app_ui::fields_writer::FieldsWriter, + parsing::types::nep413::payload::Payload, + utils::types::elipsis_fields::{ElipsisFields, EllipsisBuffer}, }; +/// length, twice as long as [crate::parsing::types::nep413::payload::NonceBuffer], +/// sufficient to store its representation as hexadecimal string. +/// NOTE: arrays only implement [Default] up to 32 in size +const NONCE_HEX_LENGTH: usize = 64; + struct FieldsContext { - msg_display_buf: [u8; 20], - nonce_buffer: [u8; 64], - recipient_display_buf: [u8; 20], - callback_url_display_buf: [u8; 20], + msg_display_buf: EllipsisBuffer, + nonce_buffer: [u8; NONCE_HEX_LENGTH], + recipient_display_buf: EllipsisBuffer, + callback_url_display_buf: EllipsisBuffer, } impl FieldsContext { pub fn new() -> Self { Self { - msg_display_buf: [0u8; 20], - nonce_buffer: [0u8; 64], - recipient_display_buf: [0u8; 20], - callback_url_display_buf: [0u8; 20], + msg_display_buf: EllipsisBuffer::default(), + nonce_buffer: [0u8; NONCE_HEX_LENGTH], + recipient_display_buf: EllipsisBuffer::default(), + callback_url_display_buf: EllipsisBuffer::default(), } } } +/// Message `ElipsisFields` (1-2) + Nonce (1) + +/// Recipient `ElipsisFields` (1-2) + Callback Url (1-2) +const MAX_FIELDS: usize = 7; + fn format<'b, 'a: 'b>( payload: &'b mut Payload, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 7>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { - // 2 let message_fields = ElipsisFields::from_capped_string( &mut payload.message, "Message", @@ -39,7 +48,6 @@ fn format<'b, 'a: 'b>( ); writer.push_fields(message_fields); - // 3 // .unwrap() is ok, as `64 == 32 * 2` holds true hex::encode_to_slice(payload.nonce, &mut field_context.nonce_buffer).unwrap(); writer.push_fields(ElipsisFields::one(Field { @@ -48,7 +56,6 @@ fn format<'b, 'a: 'b>( value: core::str::from_utf8(&field_context.nonce_buffer).unwrap(), })); - // 5 let recipient_fields = ElipsisFields::from_capped_string( &mut payload.recipient, "Recipient", @@ -56,7 +63,6 @@ fn format<'b, 'a: 'b>( ); writer.push_fields(recipient_fields); - // 7 if let Some(callback_url) = payload.callback_url.as_mut() { let callback_url_fields = ElipsisFields::from_capped_string( callback_url, @@ -67,7 +73,7 @@ fn format<'b, 'a: 'b>( } } pub fn ui_display(payload: &mut Payload) -> bool { - let mut field_writer: FieldsWriter<'_, 7> = FieldsWriter::new(); + let mut field_writer = FieldsWriter::new(); let mut field_context: FieldsContext = FieldsContext::new(); format(payload, &mut field_context, &mut field_writer); diff --git a/src/app_ui/sign/transaction/prefix.rs b/src/app_ui/sign/transaction/prefix.rs index 9c2b590..11bcd9e 100644 --- a/src/app_ui/sign/transaction/prefix.rs +++ b/src/app_ui/sign/transaction/prefix.rs @@ -5,29 +5,34 @@ use ledger_device_sdk::ui::{ use numtoa::NumToA; use crate::{ - app_ui::fields_writer::FieldsWriter, parsing, utils::types::elipsis_fields::ElipsisFields, + app_ui::{aliases::U32Buffer, fields_writer::FieldsWriter}, + parsing, + utils::types::elipsis_fields::{ElipsisFields, EllipsisBuffer}, }; struct FieldsContext { - display_buf1: [u8; 20], - display_buf2: [u8; 20], - numtoa_buf: [u8; 10], + display_buf1: EllipsisBuffer, + display_buf2: EllipsisBuffer, + numtoa_buf: U32Buffer, } impl FieldsContext { pub fn new() -> Self { Self { - display_buf1: [0u8; 20], - display_buf2: [0u8; 20], - numtoa_buf: [0u8; 10], + display_buf1: EllipsisBuffer::default(), + display_buf2: EllipsisBuffer::default(), + numtoa_buf: U32Buffer::default(), } } } +/// Signer Id (1-2) + Receiver Id (1-2) + Total actions (1) +const MAX_FIELDS: usize = 5; + fn format<'b, 'a: 'b>( prefix: &'b mut parsing::types::transaction::prefix::Prefix, field_context: &'a mut FieldsContext, - writer: &'_ mut FieldsWriter<'b, 5>, + writer: &'_ mut FieldsWriter<'b, MAX_FIELDS>, ) { let signer_id = ElipsisFields::from_capped_string( &mut prefix.signer_id, @@ -53,7 +58,7 @@ fn format<'b, 'a: 'b>( })); } pub fn ui_display(prefix: &mut parsing::types::transaction::prefix::Prefix) -> bool { - let mut field_writer: FieldsWriter<'_, 5> = FieldsWriter::new(); + let mut field_writer = FieldsWriter::new(); let mut field_context: FieldsContext = FieldsContext::new(); format(prefix, &mut field_context, &mut field_writer); diff --git a/src/app_ui/sign/widgets.rs b/src/app_ui/sign/widgets.rs index e094282..b5f1177 100644 --- a/src/app_ui/sign/widgets.rs +++ b/src/app_ui/sign/widgets.rs @@ -20,6 +20,8 @@ use ledger_device_sdk::ui::gadgets::clear_screen; use ledger_device_sdk::ui::layout::{Layout, Location, StringPlace}; use ledger_device_sdk::ui::screen_util::screen_update; +/// the constants and their special meaning were copied from +/// [ledger_device_sdk::ui::gadgets::display_pending_review] pub fn display_receiving() { clear_screen(); diff --git a/src/handlers/common/action/function_call.rs b/src/handlers/common/action/function_call.rs index 049a3ff..75c8b0a 100644 --- a/src/handlers/common/action/function_call.rs +++ b/src/handlers/common/action/function_call.rs @@ -1,7 +1,7 @@ +use crate::app_ui::aliases::{FnCallCappedString, FnCallHexDisplay}; use crate::parsing::types::FunctionCallCommon; use crate::sign_ui; use crate::utils::types::capped_string::CappedString; -use crate::utils::types::hex_display::HexDisplay; use crate::{ parsing::{HashingStream, SingleTxStream}, AppSW, @@ -31,10 +31,10 @@ pub fn handle( { // '{' char Some(123) => { - let mut args_str: CappedString<200> = CappedString::new(); + let mut args_str: FnCallCappedString = FnCallCappedString::new(); match args_str.deserialize_with_bytes_count(stream, args_bytes_count) { Err(err) if err.kind() == ErrorKind::InvalidData => { - let mut args_bin: HexDisplay<200> = args_str.into(); + let mut args_bin: FnCallHexDisplay = args_str.into(); args_bin.reformat(); ArgsRepr::BinHex(args_bin) } @@ -45,7 +45,7 @@ pub fn handle( } } Some(_first_byte) => { - let mut args_bin: HexDisplay<200> = HexDisplay::new(); + let mut args_bin: FnCallHexDisplay = FnCallHexDisplay::new(); args_bin .deserialize_with_bytes_count(stream, args_bytes_count) .map_err(|_err| AppSW::TxParsingFail)?; @@ -92,6 +92,6 @@ fn handle_common( } enum ArgsRepr { - String(CappedString<200>), - BinHex(HexDisplay<200>), + String(FnCallCappedString), + BinHex(FnCallHexDisplay), } diff --git a/src/main.rs b/src/main.rs index 4301ddf..b820f6c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,7 @@ mod utils { } mod app_ui { pub mod address; + pub mod aliases; pub mod fields_writer; pub mod menu; pub mod sign { diff --git a/src/parsing/types/common/action/add_key.rs b/src/parsing/types/common/action/add_key.rs index ea2bf2c..bb89688 100644 --- a/src/parsing/types/common/action/add_key.rs +++ b/src/parsing/types/common/action/add_key.rs @@ -1,7 +1,7 @@ +use crate::app_ui::aliases::{CappedAccountId, MethodNamesBuffer}; use crate::{parsing::types::TxPublicKey, utils::types::capped_string::CappedString}; use borsh::io::{Error, ErrorKind, Read, Result}; use borsh::BorshDeserialize; -use fmt_buffer::Buffer; use near_token::NearToken; use super::Nonce; @@ -44,14 +44,14 @@ pub struct FunctionCallPermission { // values for this field (see: https://github.com/near/nearcore/pull/4621#issuecomment-892099860) // we accommodate those by using a string, allowing us to read and parse genesis. /// The access key only allows transactions with the given receiver's account id. - pub receiver_id: CappedString<64>, + pub receiver_id: CappedAccountId, pub number_of_method_names: u32, /// A list of method names that can be used. The access key only allows transactions with the /// function call of one of the given method names. /// Empty list means any method name can be used. // pub method_names: Vec, - pub method_names: Buffer<210>, + pub method_names: MethodNamesBuffer, } impl BorshDeserialize for AccessKeyPermission { @@ -83,13 +83,19 @@ impl BorshDeserialize for AddKey { } } +/// buffer to store each individual `method_name` in `method_names` of +/// https://docs.rs/near-primitives/0.21.2/near_primitives/account/struct.FunctionCallPermission.html . +/// If a `method_name` is longer than this buffer during parsing, it's +/// truncated and will be displayed with ellipsis `is_too_long_method_name_suffix_truncated...` +type PerMethodBuffer = CappedString<40>; + impl FunctionCallPermission { pub fn new() -> Self { Self { allowance: None, - receiver_id: CappedString::new(), + receiver_id: CappedAccountId::new(), number_of_method_names: 0, - method_names: Buffer::new(), + method_names: MethodNamesBuffer::new(), } } // NOTE: using this instead of `BorshDeserialize` @@ -101,7 +107,7 @@ impl FunctionCallPermission { self.number_of_method_names = BorshDeserialize::deserialize_reader(reader)?; - let mut per_method_buffer: CappedString<40> = CappedString::new(); + let mut per_method_buffer: PerMethodBuffer = PerMethodBuffer::new(); for _i in 0..(self.number_of_method_names as usize) { per_method_buffer.deserialize_reader_in_place(reader)?; diff --git a/src/parsing/types/common/action/delete_account.rs b/src/parsing/types/common/action/delete_account.rs index e45e0f1..929c56e 100644 --- a/src/parsing/types/common/action/delete_account.rs +++ b/src/parsing/types/common/action/delete_account.rs @@ -1,14 +1,14 @@ -use crate::utils::types::capped_string::CappedString; +use crate::app_ui::aliases::CappedAccountId; use borsh::io::{Read, Result}; pub struct DeleteAccount { - pub beneficiary_id: CappedString<64>, + pub beneficiary_id: CappedAccountId, } impl DeleteAccount { pub fn new() -> Self { Self { - beneficiary_id: CappedString::new(), + beneficiary_id: CappedAccountId::new(), } } pub fn deserialize_reader_in_place(&mut self, reader: &mut R) -> Result<()> { diff --git a/src/parsing/types/common/action/deploy_contract.rs b/src/parsing/types/common/action/deploy_contract.rs index f3fb6de..72ee11c 100644 --- a/src/parsing/types/common/action/deploy_contract.rs +++ b/src/parsing/types/common/action/deploy_contract.rs @@ -3,8 +3,13 @@ use crate::utils::types::base58_buf::Base58Buf; use borsh::io::{Error, ErrorKind, Read, Result}; use borsh::BorshDeserialize; +/// arbitrary chunk size, which is set to around 40% of apdu buffer size +/// in order to not consume much stack space on `nanos` +const CHUNK_SIZE: usize = 100; + pub struct DeployContract { /// WebAssembly binary (hash) + /// 50 bytes is enough to store base58 of a sha256 hash pub code_sha256: Base58Buf<50>, } @@ -12,10 +17,10 @@ impl BorshDeserialize for DeployContract { fn deserialize_reader(reader: &mut R) -> Result { let bytes_count: u32 = u32::deserialize_reader(reader)?; - let mut buf: [u8; 100] = [0u8; 100]; + let mut buf: [u8; CHUNK_SIZE] = [0u8; CHUNK_SIZE]; - let chunks = bytes_count / 100; - let remainder = bytes_count % 100; + let chunks = bytes_count / (CHUNK_SIZE as u32); + let remainder = bytes_count % (CHUNK_SIZE as u32); let mut stream = HashingStream::new(reader).map_err(|_err| Error::from(ErrorKind::Other))?; diff --git a/src/parsing/types/common/action/function_call.rs b/src/parsing/types/common/action/function_call.rs index a1e8f35..2362dca 100644 --- a/src/parsing/types/common/action/function_call.rs +++ b/src/parsing/types/common/action/function_call.rs @@ -5,8 +5,12 @@ use crate::utils::types::capped_string::CappedString; use borsh::io::{Read, Result}; use borsh::BorshDeserialize; +/// a buffer for storing `method_name`, long enough +/// for most of practical cases +type MethodNameBuffer = CappedString<50>; + pub struct FunctionCallCommon { - pub method_name: CappedString<50>, + pub method_name: MethodNameBuffer, pub gas: NearGas, pub deposit: NearToken, } @@ -14,7 +18,7 @@ pub struct FunctionCallCommon { impl FunctionCallCommon { pub fn deserialize_with_method_name( reader: &mut R, - method_name: CappedString<50>, + method_name: MethodNameBuffer, ) -> Result { let gas: NearGas = BorshDeserialize::deserialize_reader(reader)?; let deposit: NearToken = BorshDeserialize::deserialize_reader(reader)?; diff --git a/src/parsing/types/nep366_delegate_action/prefix.rs b/src/parsing/types/nep366_delegate_action/prefix.rs index 55c5cf0..e865085 100644 --- a/src/parsing/types/nep366_delegate_action/prefix.rs +++ b/src/parsing/types/nep366_delegate_action/prefix.rs @@ -1,20 +1,20 @@ -use crate::utils::types::capped_string::CappedString; +use crate::app_ui::aliases::CappedAccountId; use borsh::io::{Read, Result}; use borsh::BorshDeserialize; pub struct Prefix { /// Signer of the delegated actions - pub sender_id: CappedString<64>, + pub sender_id: CappedAccountId, /// Receiver of the delegated actions. - pub receiver_id: CappedString<64>, + pub receiver_id: CappedAccountId, pub number_of_actions: u32, } impl Prefix { pub fn new() -> Self { Self { - sender_id: CappedString::new(), - receiver_id: CappedString::new(), + sender_id: CappedAccountId::new(), + receiver_id: CappedAccountId::new(), number_of_actions: 0, } } diff --git a/src/parsing/types/nep413/payload.rs b/src/parsing/types/nep413/payload.rs index fd9e5da..9bd38d7 100644 --- a/src/parsing/types/nep413/payload.rs +++ b/src/parsing/types/nep413/payload.rs @@ -1,28 +1,38 @@ +use crate::app_ui::aliases::{CappedAccountId, NEP413CappedString}; use crate::utils::types::capped_string::CappedString; use borsh::io::{Error, ErrorKind, Read, Result}; use borsh::BorshDeserialize; +/// buffer to store nonce, corresponding to +/// https://github.com/near/NEPs/blob/master/neps/nep-0413.md and +/// `nonce` field of https://docs.rs/near-ledger/0.5.0/near_ledger/struct.NEP413Payload.html +pub type NonceBuffer = [u8; 32]; + +/// a buffer for storing `callback_url`, should be long enough +/// for most of practical cases +pub type CappedCallbackUrl = CappedString<100>; + pub struct Payload { - pub message: CappedString<400>, - pub nonce: [u8; 32], - pub recipient: CappedString<64>, - pub callback_url: Option>, + pub message: NEP413CappedString, + pub nonce: NonceBuffer, + pub recipient: CappedAccountId, + pub callback_url: Option, } impl Payload { pub fn new() -> Self { Self { - message: CappedString::new(), - nonce: [0u8; 32], - recipient: CappedString::new(), - callback_url: Some(CappedString::new()), + message: NEP413CappedString::new(), + nonce: NonceBuffer::default(), + recipient: CappedAccountId::new(), + callback_url: Some(CappedCallbackUrl::new()), } } /// must be only called once after `Self::new` to avoid unexpected panics pub fn deserialize_reader_in_place(&mut self, reader: &mut R) -> Result<()> { self.message.deserialize_reader_in_place(reader)?; - let nonce: [u8; 32] = BorshDeserialize::deserialize_reader(reader)?; + let nonce: NonceBuffer = BorshDeserialize::deserialize_reader(reader)?; self.nonce = nonce; self.recipient.deserialize_reader_in_place(reader)?; diff --git a/src/parsing/types/transaction/prefix/mod.rs b/src/parsing/types/transaction/prefix/mod.rs index a519299..85bd59d 100644 --- a/src/parsing/types/transaction/prefix/mod.rs +++ b/src/parsing/types/transaction/prefix/mod.rs @@ -1,14 +1,16 @@ -use crate::{parsing::types::TxPublicKey, utils::types::capped_string::CappedString}; +use crate::app_ui::aliases::CappedAccountId; +use crate::parsing::types::TxPublicKey; use borsh::io::{Read, Result}; use borsh::BorshDeserialize; pub struct Prefix { - pub signer_id: CappedString<64>, - pub receiver_id: CappedString<64>, + pub signer_id: CappedAccountId, + pub receiver_id: CappedAccountId, pub public_key: TxPublicKey, pub number_of_actions: u32, } +/// hash, which is `sha2::Sha256` pub struct CryptoHash(pub [u8; 32]); impl BorshDeserialize for CryptoHash { @@ -20,8 +22,8 @@ impl BorshDeserialize for CryptoHash { impl Prefix { pub fn new() -> Self { Self { - signer_id: CappedString::new(), - receiver_id: CappedString::new(), + signer_id: CappedAccountId::new(), + receiver_id: CappedAccountId::new(), public_key: TxPublicKey::ED25519([0u8; 32]), number_of_actions: 0, } @@ -33,9 +35,7 @@ impl Prefix { let pk: TxPublicKey = BorshDeserialize::deserialize_reader(reader)?; self.public_key = pk; - let nonce: u64 = BorshDeserialize::deserialize_reader(reader)?; - #[allow(dropping_copy_types)] - drop(nonce); + let _nonce: u64 = BorshDeserialize::deserialize_reader(reader)?; self.receiver_id.deserialize_reader_in_place(reader)?; let _crypto_hash: CryptoHash = BorshDeserialize::deserialize_reader(reader)?; diff --git a/src/utils/types/elipsis_fields.rs b/src/utils/types/elipsis_fields.rs index dab72ed..37e6312 100644 --- a/src/utils/types/elipsis_fields.rs +++ b/src/utils/types/elipsis_fields.rs @@ -1,6 +1,8 @@ use ledger_device_sdk::ui::gadgets::Field; use numtoa::NumToA; +use crate::app_ui::aliases::U32Buffer; + use super::{ capped_string::CappedString, hex_display::HexDisplay, @@ -9,6 +11,10 @@ use super::{ use fmt_buffer::Buffer; +/// A buffer, large enough to contain string with number of leftover bytes: `... N bytes` +/// where N is u32 +pub type EllipsisBuffer = [u8; 20]; + pub enum ElipsisFields<'a> { One([Field<'a>; 1]), Two([Field<'a>; 2]), @@ -22,10 +28,10 @@ impl<'a> ElipsisFields<'a> { pub fn from_fmt_buffer( source: &'a mut Buffer, title: &'a str, - display_buf: &'a mut [u8; 20], + display_buf: &'a mut EllipsisBuffer, ) -> Self { if source.truncated() { - let mut numtoa_buf = [0u8; 10]; + let mut numtoa_buf = U32Buffer::default(); let elipsis_descr = strcat::concatenate( &[ @@ -48,20 +54,20 @@ impl<'a> ElipsisFields<'a> { }, ]) } else { - return ElipsisFields::One([Field { + ElipsisFields::One([Field { name: title, value: source.as_str(), - }]); + }]) } } pub fn from_hex_display( source: &'a HexDisplay, title: &'a str, - display_buf: &'a mut [u8; 20], + display_buf: &'a mut EllipsisBuffer, ) -> Self { if source.truncated() { - let mut numtoa_buf = [0u8; 10]; + let mut numtoa_buf = U32Buffer::default(); let elipsis_descr = concatenate( &[ @@ -84,20 +90,20 @@ impl<'a> ElipsisFields<'a> { }, ]) } else { - return ElipsisFields::One([Field { + ElipsisFields::One([Field { name: title, value: source.as_str(), - }]); + }]) } } pub fn from_capped_string( source: &'a mut CappedString, title: &'a str, - display_buf: &'a mut [u8; 20], + display_buf: &'a mut EllipsisBuffer, ) -> Self { if source.truncated() { - let mut numtoa_buf = [0u8; 10]; + let mut numtoa_buf = U32Buffer::default(); let elipsis_descr = strcat::concatenate( &[ @@ -120,10 +126,10 @@ impl<'a> ElipsisFields<'a> { }, ]) } else { - return ElipsisFields::One([Field { + ElipsisFields::One([Field { name: title, value: source.as_str(), - }]); + }]) } } }