From a049cf26369351ad2bd11475db098d562a86f15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dj8yf0=CE=BCl?= Date: Thu, 25 Jan 2024 21:40:03 +0200 Subject: [PATCH] feat: impl `Stake` action --- src/app_ui/sign/action.rs | 10 ++++++ src/app_ui/sign/action/delete_key.rs | 4 +-- src/app_ui/sign/action/stake.rs | 52 ++++++++++++++++++++++++++++ src/handlers/sign_tx.rs | 2 ++ src/handlers/sign_tx/stake.rs | 21 +++++++++++ src/main.rs | 2 +- src/parsing/types/action/mod.rs | 4 ++- src/parsing/types/action/stake.rs | 39 +++++++++++++++++++++ 8 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 src/app_ui/sign/action/stake.rs create mode 100644 src/handlers/sign_tx/stake.rs create mode 100644 src/parsing/types/action/stake.rs diff --git a/src/app_ui/sign/action.rs b/src/app_ui/sign/action.rs index 079b7e4..1b5fcca 100644 --- a/src/app_ui/sign/action.rs +++ b/src/app_ui/sign/action.rs @@ -9,6 +9,7 @@ use numtoa::NumToA; mod create_account; mod delete_account; mod delete_key; +mod stake; mod transfer; pub fn ui_display_transfer( @@ -61,6 +62,15 @@ pub fn ui_display_delete_key( ui_display_common(&mut writer, ordinal, total_actions) } +pub fn ui_display_stake(stake: &parsing::types::Stake, ordinal: u32, total_actions: u32) -> bool { + let mut field_context: stake::FieldsContext = stake::FieldsContext::new(); + let mut writer: FieldsWriter<'_, 3> = FieldsWriter::new(); + + stake::format(stake, &mut field_context, &mut writer); + + ui_display_common(&mut writer, ordinal, total_actions) +} + pub fn ui_display_common( writer: &mut FieldsWriter<'_, N>, ordinal: u32, diff --git a/src/app_ui/sign/action/delete_key.rs b/src/app_ui/sign/action/delete_key.rs index 0b7c953..5a3ce6b 100644 --- a/src/app_ui/sign/action/delete_key.rs +++ b/src/app_ui/sign/action/delete_key.rs @@ -7,7 +7,7 @@ use crate::{ }; pub struct FieldsContext { - buffer: FmtBuffer<100>, + pub buffer: FmtBuffer<100>, } impl FieldsContext { @@ -17,7 +17,7 @@ impl FieldsContext { } } - fn format_public_key(&mut self, public_key: &TxPublicKey) { + pub fn format_public_key(&mut self, public_key: &TxPublicKey) { match public_key { TxPublicKey::ED25519(arr) => { let mut tmp_buf = [0u8; 50]; diff --git a/src/app_ui/sign/action/stake.rs b/src/app_ui/sign/action/stake.rs new file mode 100644 index 0000000..47c5a4f --- /dev/null +++ b/src/app_ui/sign/action/stake.rs @@ -0,0 +1,52 @@ +use crate::parsing::{self, types::action::ONE_NEAR}; +use ledger_device_sdk::ui::gadgets::Field; + +use crate::{app_ui::fields_writer::FieldsWriter, utils::types::capped_string::ElipsisFields}; + +use super::delete_key; + +pub struct FieldsContext { + pub float_buffer: dtoa::Buffer, + pub pub_key_context: delete_key::FieldsContext, +} + +impl FieldsContext { + pub fn new() -> Self { + Self { + float_buffer: dtoa::Buffer::new(), + pub_key_context: delete_key::FieldsContext::new(), + } + } +} + +pub fn format<'b, 'a: 'b>( + stake: &parsing::types::Stake, + field_context: &'a mut FieldsContext, + writer: &'_ mut FieldsWriter<'b, 3>, +) { + let stake_amount = (stake.stake as f64) / (ONE_NEAR as f64); + let printed_amount = field_context.float_buffer.format(stake_amount); + field_context + .pub_key_context + .format_public_key(&stake.public_key); + writer + .push_fields(ElipsisFields::one(Field { + name: "Action type:", + value: "Stake", + })) + .unwrap(); + + writer + .push_fields(ElipsisFields::one(Field { + name: "Stake (NEAR)", + value: printed_amount, + })) + .unwrap(); + + writer + .push_fields(ElipsisFields::one(Field { + name: "Public Key:", + value: field_context.pub_key_context.buffer.as_str(), + })) + .unwrap(); +} diff --git a/src/handlers/sign_tx.rs b/src/handlers/sign_tx.rs index f8ef1f6..3594697 100644 --- a/src/handlers/sign_tx.rs +++ b/src/handlers/sign_tx.rs @@ -36,6 +36,7 @@ pub struct Signature(pub [u8; 64]); pub mod create_account; pub mod delete_account; pub mod delete_key; +pub mod stake; pub mod transfer; fn popup_transaction_prefix(stream: &mut HashingStream>) -> Result { @@ -67,6 +68,7 @@ fn popup_action( Action::CreateAccount => create_account::handle(stream, ordinal_action, total_actions), Action::DeleteAccount => delete_account::handle(stream, ordinal_action, total_actions), Action::DeleteKey => delete_key::handle(stream, ordinal_action, total_actions), + Action::Stake => stake::handle(stream, ordinal_action, total_actions), _ => unimplemented!(), } } diff --git a/src/handlers/sign_tx/stake.rs b/src/handlers/sign_tx/stake.rs new file mode 100644 index 0000000..93fddf5 --- /dev/null +++ b/src/handlers/sign_tx/stake.rs @@ -0,0 +1,21 @@ +use crate::sign_ui; +use crate::{ + parsing::{borsh::BorshDeserialize, types::Stake, HashingStream, SingleTxStream}, + AppSW, +}; + +pub fn handle( + stream: &mut HashingStream>, + ordinal_action: u32, + total_actions: u32, +) -> Result<(), AppSW> { + let stake = Stake::deserialize_reader(stream).map_err(|_err| AppSW::TxParsingFail)?; + + #[cfg(feature = "speculos")] + stake.debug_print(); + + if !sign_ui::action::ui_display_stake(&stake, ordinal_action + 1, total_actions) { + return Err(AppSW::Deny); + } + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 8be95d4..7cfa944 100644 --- a/src/main.rs +++ b/src/main.rs @@ -62,7 +62,7 @@ pub mod parsing { pub use action::{ create_account::CreateAccount, delete_account::DeleteAccount, delete_key::DeleteKey, - transfer::Transfer, Action, + stake::Stake, transfer::Transfer, Action, }; pub use transaction_prefix::TransactionPrefix; } diff --git a/src/parsing/types/action/mod.rs b/src/parsing/types/action/mod.rs index 8f80e81..786b1aa 100644 --- a/src/parsing/types/action/mod.rs +++ b/src/parsing/types/action/mod.rs @@ -11,6 +11,7 @@ pub const ONE_NEAR: Balance = 1_000_000_000_000_000_000_000_000; pub mod create_account; pub mod delete_account; pub mod delete_key; +pub mod stake; pub mod transfer; pub enum Action { @@ -29,9 +30,10 @@ impl BorshDeserialize for Action { fn deserialize_reader(reader: &mut R) -> Result { let variant_tag = u8::deserialize_reader(reader)?; match variant_tag { - 1 | 2 | 4 | 5 | 8 => unimplemented!("stub for other variants"), + 1 | 2 | 5 | 8 => unimplemented!("stub for other variants"), 0 => Ok(Self::CreateAccount), 3 => Ok(Self::Transfer), + 4 => Ok(Self::Stake), 6 => Ok(Self::DeleteKey), 7 => Ok(Self::DeleteAccount), _ => { diff --git a/src/parsing/types/action/stake.rs b/src/parsing/types/action/stake.rs new file mode 100644 index 0000000..9a80b6e --- /dev/null +++ b/src/parsing/types/action/stake.rs @@ -0,0 +1,39 @@ +use crate::{ + io::{Read, Result}, + parsing::{borsh::BorshDeserialize, types::tx_public_key::TxPublicKey}, +}; + +use super::Balance; + +pub struct Stake { + /// Amount of tokens to stake. + pub stake: Balance, + /// Validator key which will be used to sign transactions on behalf of signer_id + pub public_key: TxPublicKey, +} + +impl BorshDeserialize for Stake { + fn deserialize_reader(rd: &mut R) -> Result { + let stake = u128::deserialize_reader(rd)?; + Ok(Self { + stake, + public_key: BorshDeserialize::deserialize_reader(rd)?, + }) + } +} + +impl Stake { + #[cfg(feature = "speculos")] + pub fn debug_print(&self) { + use ledger_device_sdk::testing; + use numtoa::NumToA; + + let mut numtoa_buf = [0u8; 40]; + + testing::debug_print("debug printing stake action:\n"); + testing::debug_print("size of self: \n"); + testing::debug_print(core::mem::size_of_val(self).numtoa_str(10, &mut numtoa_buf)); + testing::debug_print("\n"); + testing::debug_print("debug printing stake action finish:\n"); + } +}