What changed, and why it matters
This commit is a work-in-progress 'temp commit' that refactors Zcash support in the Keystone 3 firmware. It moves Zcash UI code from a 'cypherpunk' build variant into the standard multi-coin build, splits a combined Zcash UFVK/seed-fingerprint getter into separate functions, adds a new Zcash seed fingerprint parameter to the Keystone Connect wallet QR/UR generation, and enables the 'zcash' feature in the Rust multi-coins build. There is no clear security fix or vulnerability being patched; it appears to be feature plumbing and code reorganisation.
Treat this as a non-security, work-in-progress refactor. If reviewing for release, verify that the new seed_fingerprint metadata is intended for public exposure in the UR, that the `#ifndef BTC_ONLY` guard does not accidentally enable Zcash code in unintended builds, and that the deleted cypherpunk files are fully replaced without losing any security checks. No immediate patch or incident response is indicated by the diff alone.
Security signals we found
New sensitive data field (32-byte Zcash seed fingerprint) is added to a wallet connection QR/UR payload
Refactoring of Zcash UFVK and seed-fingerprint cache accessors changes which build configurations include the code (`#ifndef BTC_ONLY` instead of `#ifdef CYPHERPUNK_VERSION`)
Debug print statements for xpub chain code and key path were removed, reducing information leakage in logs
Commit title is 'test: temp commit', indicating unfinished work
Evidence from the diff
The diff shows: (1) rust/rust_c/Cargo.toml adds ‘zcash’ to the multi-coins feature list, broadening the build configuration. (2) keystone_connect.rs (Rust app and C FFI) gains a new zcash_seed_fingerprint argument; for ZEC derivation paths it embeds {"seed_fingerprint":<hex>} as extra key metadata in the generated CryptoMultiAccounts UR. (3) account_public_info.h adds ZCASH_UFVK_ENCRYPTED_0. (4) account_manager.c/h and keystore.c replace #ifdef CYPHERPUNK_VERSION guards around Zcash cache handling with #ifndef BTC_ONLY, rename CalculateZcashUFVK to SetupZcashCache, and split GetZcashUFVK/SetZcashUFVK into separate UFVK and seed-fingerprint getters/setters. (5) The old gui_chain/multi/cypherpunk/gui_zcash.c/h files are deleted and recreated under gui_chain/multi/gui_zcash.c/h, with call sites updated to use the separate getters. (6) gui_wallet.c now passes the Zcash seed fingerprint into get_keystone_connect_wallet_ur. No explicit security issue is described or fixed in the commit message or code comments.
Changed components
rust/apps/wallets/src/keystone_connect.rsrust/rust_c/Cargo.tomlrust/rust_c/src/wallet/multi_coins_wallet/keystone_connect.rssrc/crypto/account_public_info.hsrc/managers/account_manager.csrc/managers/account_manager.hsrc/managers/keystore.csrc/ui/gui_chain/multi/cypherpunk/gui_zcash.csrc/ui/gui_chain/multi/cypherpunk/gui_zcash.hsrc/ui/gui_chain/multi/gui_zcash.csrc/ui/gui_chain/multi/gui_zcash.hsrc/ui/gui_wallet/multi/web3/gui_wallet.csrc/ui/gui_widgets/multi/cypherpunk/gui_connect_wallet_widgets.csrc/ui/gui_widgets/multi/gui_standard_receive_widgets.cInspect captured patch +427 / −372
diff --git a/rust/apps/wallets/src/keystone_connect.rs b/rust/apps/wallets/src/keystone_connect.rs
index a5e4d2c..eb5ecdf 100644
--- a/rust/apps/wallets/src/keystone_connect.rs
+++ b/rust/apps/wallets/src/keystone_connect.rs
@@ -3,6 +3,7 @@ use alloc::{
vec::Vec,
};
use core::str::FromStr;
+use serde_json::json;
use {
bitcoin::bip32::{ChildNumber, DerivationPath},
@@ -42,10 +43,11 @@ pub fn generate_crypto_multi_accounts(
extended_public_keys: Vec<ExtendedPublicKey>,
device_type: &str,
device_version: &str,
+ zcash_seed_fingerprint: Option<[u8; 32]>,
) -> URResult<CryptoMultiAccounts> {
let device_id = get_device_id(serial_number);
let mut keys = vec![];
- let k1_keys = [
+ let k1_normal_keys = [
BTC_LEGACY_PREFIX.to_string(),
BTC_SEGWIT_PREFIX.to_string(),
BTC_NATIVE_SEGWIT_PREFIX.to_string(),
@@ -57,9 +59,27 @@ pub fn generate_crypto_multi_accounts(
LTC_NATIVE_SEGWIT_PREFIX.to_string(),
ZEC_PREFIX.to_string(),
];
- for ele in extended_public_keys {
+ for ele in extended_public_keys {
match ele.get_path() {
- _path if k1_keys.contains(&_path.to_string().to_lowercase()) => {
+ _path if _path.to_string().to_lowercase().eq(ZEC_PREFIX) => {
+ let json = if let Some(fingerprint) = zcash_seed_fingerprint {
+ Some(
+ json!({
+ "seed_fingerprint": hex::encode(fingerprint)
+ })
+ .to_string(),
+ )
+ } else {
+ None
+ };
+ keys.push(generate_k1_normal_key(
+ master_fingerprint,
+ ele.clone(),
+ json,
+ false,
+ )?);
+ }
+ _path if k1_normal_keys.contains(&_path.to_string().to_lowercase()) => {
keys.push(generate_k1_normal_key(
master_fingerprint,
ele.clone(),
@@ -174,9 +194,6 @@ fn generate_k1_normal_key(
Some(xpub.depth as u32),
);
- rust_tools::debug_print!("generate_k1_normal_key key_path: {:?}", key_path);
- rust_tools::debug_print!("generate_k1_normal_key xpub chaincode: {:?}", hex::encode(xpub.chain_code.to_bytes()));
-
let children = CryptoKeyPath::new(
match is_standard {
true => {
@@ -396,6 +413,7 @@ mod tests {
],
DEVICE_TYPE,
"1.1.0",
+ None,
)
.unwrap();
let cbor: Vec<u8> = account.try_into().unwrap();
@@ -428,9 +446,15 @@ mod tests {
ExtendedPublicKey::new(DerivationPath::from_str("m/86'/0'/0'").unwrap(), hex::decode("0488b21e030484004d80000000a75805b89c5079ba74e9002c3e587f7c97ea8018ab1d5245638a45de3c845e0b03e0db6ca7c71e72a40091141b9dc4596ab3a9192ac41eebe1f2b048c654423ecb").unwrap()),
];
- let account =
- generate_crypto_multi_accounts(mfp, serial_number, keys, device_type, device_version)
- .unwrap();
+ let account = generate_crypto_multi_accounts(
+ mfp,
+ serial_number,
+ keys,
+ device_type,
+ device_version,
+ None,
+ )
+ .unwrap();
let cbor: Vec<u8> = account.try_into().unwrap();
assert_eq!(hex::encode(cbor), "a5011a1250b6bc0290d9012fa802f403582103c4ad25226a98764f7b753b6c763be112c940182e0b6698944c9def253cec4676045820bf103cfabcab325a7463ab5c432a4042109279d6c3531c8c5ea712684cf31f3706d90130a30186182cf5183cf500f5021a1250b6bc030307d90130a2018400f480f40300081a63c5ea6709684b657973746f6e650a706163636f756e742e7374616e64617264d9012fa602f403582103346d8362d8b3c348cc821abe96e79bbc005af54567d0742c9052215322eaa08a06d90130a30188182cf5183cf500f500f4021a1250b6bc0303081a6e7c9e1809684b657973746f6e650a756163636f756e742e6c65646765725f6c6567616379d9012fa602f403582103de2f443b5070e839d6a209ed1afaadfd43daf7bc610a1fefef201a3aca5350ee06d90130a3018a182cf5183cf500f500f400f4021a1250b6bc0303081a769cd41a09684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f403582103a96bae34b46e82eee9c5beae52e446693b5c2e365714b223adea7caae47e1b7f06d90130a3018a182cf5183cf501f500f400f4021a1250b6bc0303081a998dec6209684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f4035821029299ea371a1c6cdcc75b91d26322a2dbdfedb58285e33760a2af82cfee1a7a6e06d90130a3018a182cf5183cf502f500f400f4021a1250b6bc0303081ac49452d709684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f4035821030f1808f972aed2b8e01d92b09b9c0d55b994592fb5599557e0d4828705204a4106d90130a3018a182cf5183cf503f500f400f4021a1250b6bc0303081a0823c44c09684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f4035821021c885e79f19ba2658755952801366f00f5304db8597eb72a78a6886d8175037d06d90130a3018a182cf5183cf504f500f400f4021a1250b6bc0303081aef4e5bae09684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f4035821037653d3a64a3d1fce16d5693e044e9aea644082371f4d31f6eb83096b5b84d97b06d90130a3018a182cf5183cf505f500f400f4021a1250b6bc0303081a364c571b09684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f403582103ded46d3bc515112c1c99b5f5b5f6c4abc76cc40d98ba4c1808c97038fe976ff606d90130a3018a182cf5183cf506f500f400f4021a1250b6bc0303081a456759fc09684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f403582102447d94e1937819a79a0ef56cd7b7a29de7c80a45b34480ef0b593083e418557906d90130a3018a182cf5183cf507f500f400f4021a1250b6bc0303081a09f362d709684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f403582103d94fb59028252ab9353ee376e868cfd59e9d0bc24ef35fe1b06310cd0e4e908b06d90130a3018a182cf5183cf508f500f400f4021a1250b6bc0303081a4e09767009684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa602f4035821034d53b1c2630e12b853b96d70fb671363d5d4ec9406f722b4deea1f2a9eb6e76406d90130a3018a182cf5183cf509f500f400f4021a1250b6bc0303081ac418564209684b657973746f6e650a736163636f756e742e6c65646765725f6c697665d9012fa702f40358210246696468fa5c46647bdd186f568983e2a26773dc5b4c174790fee7ef9b9a7c9904582051872c7bb8270a7655ae15d738bb21379962ff11fb048b55630395afcfef442806d90130a30186182cf500f500f5021a1250b6bc030307d90130a2018280f40300081ab5d6f45009684b657973746f6e65d9012fa702f403582103ab6a1908b437179b914dc3cf4b829d7387adf60fdee483e9c748d5ee79ba4be4045820bad8f929afd65c4b3ff78db1a386062374f2d2e6552e9fdc59aa7dd9b5db6e2c06d90130a301861831f500f500f5021a1250b6bc030307d90130a2018280f40300081a197077c809684b657973746f6e65d9012fa702f40358210262ba42544acc4223c74511b37bae54de22565f25f8034f5af8aa10a04c3621b9045820de47dd17679605b84abf439bdf5477c6cb94ff5a541d3cb1734afebfa3d3fdb906d90130a301861854f500f500f5021a1250b6bc030307d90130a2018280f40300081a9f6b7e4b09684b657973746f6e65d9012fa702f403582103e0db6ca7c71e72a40091141b9dc4596ab3a9192ac41eebe1f2b048c654423ecb045820a75805b89c5079ba74e9002c3e587f7c97ea8018ab1d5245638a45de3c845e0b06d90130a301861856f500f500f5021a1250b6bc030307d90130a2018280f40300081a0484004d09684b657973746f6e65036e4b657973746f6e6520332050726f047828626339633466373135376165363937643433346163383536323332306564353335653737373638300565312e372e30");
}
diff --git a/rust/rust_c/Cargo.toml b/rust/rust_c/Cargo.toml
index cc4d59e..f116103 100644
--- a/rust/rust_c/Cargo.toml
+++ b/rust/rust_c/Cargo.toml
@@ -110,6 +110,7 @@ multi-coins = [
"xrp",
"avalanche",
"iota",
+ "zcash"
]
btc-only = ["bitcoin"]
diff --git a/rust/rust_c/src/wallet/multi_coins_wallet/keystone_connect.rs b/rust/rust_c/src/wallet/multi_coins_wallet/keystone_connect.rs
index 5380439..dc6be84 100644
--- a/rust/rust_c/src/wallet/multi_coins_wallet/keystone_connect.rs
+++ b/rust/rust_c/src/wallet/multi_coins_wallet/keystone_connect.rs
@@ -19,6 +19,8 @@ pub unsafe extern "C" fn get_keystone_connect_wallet_ur(
public_keys: Ptr<CSliceFFI<ExtendedPublicKey>>,
device_type: PtrString,
device_version: PtrString,
+ zcash_sfp: PtrBytes,
+ zcash_sfp_length: u32,
) -> Ptr<UREncodeResult> {
if master_fingerprint_length != 4 {
return UREncodeResult::from(URError::UrEncodeError(format!(
@@ -32,6 +34,12 @@ pub unsafe extern "C" fn get_keystone_connect_wallet_ur(
Err(e) => return UREncodeResult::from(URError::UrEncodeError(e.to_string())).c_ptr(),
};
+ let sfp = extract_array!(zcash_sfp, u8, zcash_sfp_length);
+ let _sfp = match <[u8; 32]>::try_from(sfp) {
+ Ok(sfp) => sfp,
+ Err(e) => return UREncodeResult::from(URError::UrEncodeError(e.to_string())).c_ptr(),
+ };
+
let keys = recover_c_array(public_keys);
let serial_number = recover_c_char(serial_number);
let device_version = recover_c_char(device_version);
@@ -44,6 +52,7 @@ pub unsafe extern "C" fn get_keystone_connect_wallet_ur(
_keys,
&device_type,
&device_version,
+ Some(_sfp),
) {
Ok(data) => match data.try_into() {
Ok(_v) => UREncodeResult::encode(
diff --git a/src/crypto/account_public_info.h b/src/crypto/account_public_info.h
index dc3b2b8..6ab650e 100644
--- a/src/crypto/account_public_info.h
+++ b/src/crypto/account_public_info.h
@@ -237,6 +237,7 @@ typedef enum {
XPUB_TYPE_TON_NATIVE,
PUBLIC_INFO_TON_CHECKSUM,
XPUB_TYPE_ZEC_TRANSPARENT_LEGACY,
+ ZCASH_UFVK_ENCRYPTED_0,
#endif
#ifdef CYPHERPUNK_VERSION
diff --git a/src/managers/account_manager.c b/src/managers/account_manager.c
index 6412627..81148ec 100644
--- a/src/managers/account_manager.c
+++ b/src/managers/account_manager.c
@@ -32,7 +32,7 @@ static uint8_t g_lastAccountIndex = ACCOUNT_INDEX_LOGOUT;
static AccountInfo_t g_currentAccountInfo = {0};
static PublicInfo_t g_publicInfo = {0};
-#ifdef CYPHERPUNK_VERSION
+#ifndef BTC_ONLY
static ZcashUFVKCache_t g_zcashUFVKcache = {0};
static void ClearZcashUFVK();
#endif
@@ -139,8 +139,8 @@ int32_t CreateNewAccount(uint8_t accountIndex, const uint8_t *entropy, uint8_t e
ret = SaveCurrentAccountInfo();
CHECK_ERRCODE_RETURN_INT(ret);
ret = AccountPublicInfoSwitch(g_currentAccountIndex, password, true);
-#ifdef CYPHERPUNK_VERSION
- CalculateZcashUFVK(accountIndex, password);
+#ifndef BTC_ONLY
+ SetupZcashCache(accountIndex, password);
#endif
CHECK_ERRCODE_RETURN_INT(ret);
return ret;
@@ -233,7 +233,7 @@ int32_t VerifyPasswordAndLogin(uint8_t *accountIndex, const char *password)
ret = ReadCurrentAccountInfo();
g_publicInfo.loginPasswordErrorCount = 0;
g_publicInfo.currentPasswordErrorCount = 0;
-#ifdef CYPHERPUNK_VERSION
+#ifndef BTC_ONLY
ClearZcashUFVK();
#endif
if (PassphraseExist(g_currentAccountIndex)) {
@@ -244,8 +244,8 @@ int32_t VerifyPasswordAndLogin(uint8_t *accountIndex, const char *password)
printf("passphrase not exist, info switch\r\n");
ret = AccountPublicInfoSwitch(g_currentAccountIndex, password, false);
}
-#ifdef CYPHERPUNK_VERSION
- CalculateZcashUFVK(g_currentAccountIndex, password);
+#ifndef BTC_ONLY
+ SetupZcashCache(g_currentAccountIndex, password);
#endif
} else {
g_publicInfo.loginPasswordErrorCount++;
@@ -588,16 +588,19 @@ int32_t CreateNewTonAccount(uint8_t accountIndex, const char *mnemonic, const ch
}
#endif
-#ifdef CYPHERPUNK_VERSION
-static void SetZcashUFVK(uint8_t accountIndex, const char* ufvk, const uint8_t* seedFingerprint)
+#ifndef BTC_ONLY
+static void SetZcashUFVK(uint8_t accountIndex, const char* ufvk)
{
ASSERT(accountIndex <= 2);
g_zcashUFVKcache.accountIndex = accountIndex;
- ClearZcashUFVK();
strcpy_s(g_zcashUFVKcache.ufvkCache, ZCASH_UFVK_MAX_LEN, ufvk);
+}
+static void SetZcashSFP(uint8_t accountIndex, const uint8_t* seedFingerprint)
+{
+ ASSERT(accountIndex <= 2);
memcpy_s(g_zcashUFVKcache.seedFingerprint, 32, seedFingerprint, 32);
- printf("SetZcashUFVK, %s\r\n", g_zcashUFVKcache.ufvkCache);
+ printf("SetZcashSFP\r\n");
}
static void ClearZcashUFVK()
@@ -606,18 +609,27 @@ static void ClearZcashUFVK()
memset_s(g_zcashUFVKcache.seedFingerprint, 32, 0, 32);
}
-int32_t GetZcashUFVK(uint8_t accountIndex, char* outUFVK, uint8_t* outSFP)
+int32_t GetZcashUFVK(uint8_t accountIndex, char* outUFVK)
{
ASSERT(accountIndex <= 2);
if (g_zcashUFVKcache.accountIndex == accountIndex) {
strcpy_s(outUFVK, ZCASH_UFVK_MAX_LEN, g_zcashUFVKcache.ufvkCache);
+ return SUCCESS_CODE;
+ }
+ return ERR_ZCASH_INVALID_ACCOUNT_INDEX;
+}
+
+int32_t GetZcashSFP(uint8_t accountIndex, uint8_t* outSFP)
+{
+ ASSERT(accountIndex <= 2);
+ if (g_zcashUFVKcache.accountIndex == accountIndex) {
memcpy_s(outSFP, 32, g_zcashUFVKcache.seedFingerprint, 32);
return SUCCESS_CODE;
}
return ERR_ZCASH_INVALID_ACCOUNT_INDEX;
}
-int32_t CalculateZcashUFVK(uint8_t accountIndex, const char* password)
+int32_t SetupZcashCache(uint8_t accountIndex, const char* password)
{
ASSERT(accountIndex <= 2);
@@ -625,6 +637,8 @@ int32_t CalculateZcashUFVK(uint8_t accountIndex, const char* password)
return SUCCESS_CODE;
}
+ ClearZcashUFVK();
+
uint8_t seed[SEED_LEN];
int len = GetMnemonicType() == MNEMONIC_TYPE_BIP39 ? sizeof(seed) : GetCurrentAccountEntropyLen();
int32_t ret = GetAccountSeed(accountIndex, seed, password);
@@ -641,6 +655,8 @@ int32_t CalculateZcashUFVK(uint8_t accountIndex, const char* password)
char ufvk[ZCASH_UFVK_MAX_LEN] = {'\0'};
strcpy_s(ufvk, ZCASH_UFVK_MAX_LEN, response->data);
free_simple_response_c_char(response);
+ SetZcashUFVK(accountIndex, ufvk);
+
SimpleResponse_u8 *responseSFP = calculate_zcash_seed_fingerprint(seed, len);
if (responseSFP->error_code != 0) {
ret = response->error_code;
@@ -652,7 +668,7 @@ int32_t CalculateZcashUFVK(uint8_t accountIndex, const char* password)
memcpy_s(sfp, 32, responseSFP->data, 32);
free_simple_response_u8(responseSFP);
- SetZcashUFVK(accountIndex, ufvk, sfp);
+ SetZcashSFP(accountIndex, sfp);
return ret;
}
#endif
diff --git a/src/managers/account_manager.h b/src/managers/account_manager.h
index 712b210..298b5ea 100644
--- a/src/managers/account_manager.h
+++ b/src/managers/account_manager.h
@@ -101,8 +101,9 @@ uint8_t GetSlip39Eb(void);
void AccountsDataCheck(void);
-#ifdef CYPHERPUNK_VERSION
-int32_t GetZcashUFVK(uint8_t accountIndex, char* outUFVK, uint8_t* outSFP);
-int32_t CalculateZcashUFVK(uint8_t accountIndex, const char* password);
+#ifndef BTC_ONLY
+int32_t GetZcashUFVK(uint8_t accountIndex, char* outUFVK);
+int32_t GetZcashSFP(uint8_t accountIndex, uint8_t* outSFP);
+int32_t SetupZcashCache(uint8_t accountIndex, const char* password);
#endif
#endif
\ No newline at end of file
diff --git a/src/managers/keystore.c b/src/managers/keystore.c
index 89f72eb..4431273 100644
--- a/src/managers/keystore.c
+++ b/src/managers/keystore.c
@@ -370,14 +370,14 @@ int32_t SetPassphrase(uint8_t accountIndex, const char *passphrase, const char *
strcpy_s(g_passphraseInfo[accountIndex].passphrase, PASSPHRASE_MAX_LEN, passphrase);
g_passphraseInfo[accountIndex].passphraseExist = true;
ret = TempAccountPublicInfo(accountIndex, password, true);
-#ifdef CYPHERPUNK_VERSION
- CalculateZcashUFVK(accountIndex, password);
+#ifndef BTC_ONLY
+ SetupZcashCache(accountIndex, password);
#endif
} else {
ClearAccountPassphrase(accountIndex);
ret = AccountPublicInfoSwitch(accountIndex, password, false);
-#ifdef CYPHERPUNK_VERSION
- CalculateZcashUFVK(accountIndex, password);
+#ifndef BTC_ONLY
+ SetupZcashCache(accountIndex, password);
#endif
}
SetPassphraseMark(passphrase[0] != '\0');
diff --git a/src/ui/gui_chain/multi/cypherpunk/gui_zcash.c b/src/ui/gui_chain/multi/cypherpunk/gui_zcash.c
deleted file mode 100644
index fac1bc5..0000000
--- a/src/ui/gui_chain/multi/cypherpunk/gui_zcash.c
+++ /dev/null
@@ -1,321 +0,0 @@
-#include "gui_zcash.h"
-#include "gui_chain_components.h"
-#include "user_memory.h"
-#include "account_manager.h"
-#include "gui_chain.h"
-#include "keystore.h"
-#include "screen_manager.h"
-#include "gui_chain.h"
-
-#define MAX_MEMO_LENGTH 1024
-
-static bool g_isMulti = false;
-static URParseResult *g_urResult = NULL;
-static URParseMultiResult *g_urMultiResult = NULL;
-static void *g_parseResult = NULL;
-static DisplayPczt *g_zcashData;
-
-#define CHECK_FREE_PARSE_RESULT(result) \
- if (result != NULL) \
- { \
- free_TransactionParseResult_DisplayPczt((PtrT_TransactionParseResult_DisplayPczt)result); \
- result = NULL; \
- }
-
-void GuiSetZcashUrData(URParseResult *urResult, URParseMultiResult *urMultiResult, bool multi)
-{
- g_urResult = urResult;
- g_urMultiResult = urMultiResult;
- g_isMulti = multi;
-}
-
-void *GuiGetZcashGUIData(void)
-{
- CHECK_FREE_PARSE_RESULT(g_parseResult);
- void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
- char ufvk[ZCASH_UFVK_MAX_LEN] = {'\0'};
- uint8_t sfp[32];
- GetZcashUFVK(GetCurrentAccountIndex(), ufvk, sfp);
-
- PtrT_TransactionParseResult_DisplayPczt parseResult = NULL;
- do {
- parseResult = parse_zcash_tx(data, ufvk, sfp);
- CHECK_CHAIN_BREAK(parseResult);
- g_zcashData = parseResult->data;
- g_parseResult = (void *)parseResult;
-
- } while (0);
- return g_parseResult;
-}
-
-static lv_obj_t* GuiZcashOverviewTransparent(lv_obj_t *parent, lv_obj_t *last_view);
-static lv_obj_t* GuiZcashOverviewOrchard(lv_obj_t *parent, lv_obj_t *last_view);
-static lv_obj_t* GuiZcashOverviewFrom(lv_obj_t *parent, VecFFI_DisplayFrom *from, lv_obj_t *last_view);
-static lv_obj_t* GuiZcashOverviewTo(lv_obj_t *parent, VecFFI_DisplayTo *to, lv_obj_t *last_view);
-
-void GuiZcashOverview(lv_obj_t *parent, void *totalData)
-{
- lv_obj_set_size(parent, 408, 480);
- lv_obj_add_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
- lv_obj_add_flag(parent, LV_OBJ_FLAG_CLICKABLE);
-
- lv_obj_t* container = GuiCreateContainerWithParent(parent, 408, 480);
- lv_obj_add_flag(container, LV_OBJ_FLAG_SCROLLABLE);
- lv_obj_add_flag(container, LV_OBJ_FLAG_CLICKABLE);
-
- lv_obj_t* last_view = NULL;
-
- if (g_zcashData->has_sapling) {
- last_view = CreateTransactionItemView(container, _("Warning"), _("This transaction contains Sapling spends or outputs. Keystone does not support Sapling spend signing and output checking. Please take care of the potential risks."), last_view);
- }
-
- last_view = CreateTransactionItemView(container, _("Amount"), g_zcashData->total_transfer_value, last_view);
- last_view = CreateTransactionItemView(container, _("Fee"), g_zcashData->fee_value, last_view);
-
- if (g_zcashData->transparent != NULL) {
- last_view = GuiZcashOverviewTransparent(container, last_view);
- }
-
- if (g_zcashData->orchard != NULL) {
- last_view = GuiZcashOverviewOrchard(container, last_view);
- }
-}
-
-static lv_obj_t* GuiZcashOverviewTransparent(lv_obj_t *parent, lv_obj_t *last_view)
-{
- lv_obj_t* inner_last_view;
- lv_obj_t* label = GuiCreateIllustrateLabel(parent, _("Transparent"));
- lv_obj_align_to(label, last_view, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 24);
-
- inner_last_view = label;
-
- if (g_zcashData->transparent->from->size > 0) {
- lv_obj_t* from_view = GuiZcashOverviewFrom(parent, g_zcashData->transparent->from, inner_last_view);
- inner_last_view = from_view;
- }
-
- if (g_zcashData->transparent->to->size > 0) {
- lv_obj_t* to_view = GuiZcashOverviewTo(parent, g_zcashData->transparent->to, inner_last_view);
- inner_last_view = to_view;
- }
-
- return inner_last_view;
-}
-
-static lv_obj_t* GuiZcashOverviewOrchard(lv_obj_t* parent, lv_obj_t *last_view)
-{
- lv_obj_t* inner_last_view;
- lv_obj_t* label = GuiCreateIllustrateLabel(parent, _("Orchard"));
- lv_obj_align_to(label, last_view, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 24);
-
- inner_last_view = label;
-
- if (g_zcashData->orchard->from->size > 0) {
- lv_obj_t* from_view = GuiZcashOverviewFrom(parent, g_zcashData->orchard->from, inner_last_view);
- inner_last_view = from_view;
- }
-
- if (g_zcashData->orchard->to->size > 0) {
- lv_obj_t* to_view = GuiZcashOverviewTo(parent, g_zcashData->orchard->to, inner_last_view);
- inner_last_view = to_view;
- }
-
- return inner_last_view;
-}
-
-static lv_obj_t* GuiZcashOverviewFrom(lv_obj_t *parent, VecFFI_DisplayFrom *from, lv_obj_t *last_view)
-{
- lv_obj_t* label, *container;
- uint16_t height = 0;
-
- container = CreateTransactionContentContainer(parent, 408, height);
- lv_obj_align_to(container, last_view, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 24);
-
- // top padding
- height += 16;
-
- label = GuiCreateIllustrateLabel(container, _("From"));
- lv_obj_align(label, LV_ALIGN_TOP_LEFT, 24, height);
- lv_obj_set_style_text_color(label, WHITE_COLOR, LV_PART_MAIN);
- lv_obj_set_style_text_opa(label, LV_OPA_56, LV_PART_MAIN | LV_STATE_DEFAULT);
-
- height += 30;
-
- lv_obj_t *innerContainer;
-
- for (size_t i = 0; i < from->size; i++) {
- lv_obj_t *valueLabel, *indexLabel, *addressLabel;
- uint16_t innerHeight = 0;
- if (i > 0) {
- //add margin
- innerHeight += 16;
- }
- innerContainer = GuiCreateContainerWithParent(container, 360, innerHeight);
- lv_obj_set_style_bg_opa(innerContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
- lv_obj_align(innerContainer, LV_ALIGN_TOP_LEFT, 24, height);
-
- char *order = (char *)SRAM_MALLOC(5);
- snprintf_s(order, 5, "#%d", i + 1);
- indexLabel = GuiCreateIllustrateLabel(innerContainer, order);
- lv_obj_align(indexLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
-
- valueLabel = GuiCreateIllustrateLabel(innerContainer, from->data[i].value);
- lv_obj_set_style_text_color(valueLabel, ORANGE_COLOR, LV_PART_MAIN);
- lv_obj_align_to(valueLabel, indexLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
-
- if (from->data[i].is_mine) {
- lv_obj_t *tagContainer = GuiCreateContainerWithParent(innerContainer, 87, 30);
- lv_obj_set_style_radius(tagContainer, 16, LV_PART_MAIN | LV_STATE_DEFAULT);
- lv_obj_set_style_bg_color(tagContainer, WHITE_COLOR, LV_PART_MAIN | LV_STATE_DEFAULT);
- lv_obj_set_style_bg_opa(tagContainer, 30, LV_PART_MAIN | LV_STATE_DEFAULT);
- lv_obj_t *tagLabel = lv_label_create(tagContainer);
- lv_label_set_text(tagLabel, "Mine");
- lv_obj_set_style_text_font(tagLabel, g_defIllustrateFont, LV_PART_MAIN);
- lv_obj_set_style_text_color(tagLabel, WHITE_COLOR, LV_PART_MAIN);
- lv_obj_set_style_text_opa(tagLabel, 163, LV_PART_MAIN);
- lv_obj_align(tagLabel, LV_ALIGN_CENTER, 0, 0);
-
- lv_obj_align_to(tagContainer, valueLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
- }
-
- innerHeight += 30;
-
- addressLabel = GuiCreateIllustrateLabel(innerContainer, from->data[i].address);
- lv_obj_set_width(addressLabel, 360);
- lv_label_set_long_mode(addressLabel, LV_LABEL_LONG_WRAP);
- lv_obj_align(addressLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
- lv_obj_update_layout(addressLabel);
-
- innerHeight += lv_obj_get_height(addressLabel);
-
- lv_obj_set_height(innerContainer, innerHeight);
- lv_obj_update_layout(innerContainer);
-
- height += innerHeight;
- }
-
- // bottom padding
- height += 16;
-
- lv_obj_set_height(container, height);
- lv_obj_update_layout(container);
-
- return container;
-}
-
-static lv_obj_t* GuiZcashOverviewTo(lv_obj_t *parent, VecFFI_DisplayTo *to, lv_obj_t *last_view)
-{
- lv_obj_t* label, *container;
- uint16_t height = 0;
-
- container = CreateTransactionContentContainer(parent, 408, height);
- lv_obj_add_flag(container, LV_OBJ_FLAG_SCROLLABLE);
- lv_obj_add_flag(container, LV_OBJ_FLAG_CLICKABLE);
- lv_obj_align_to(container, last_view, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 24);
-
- // top padding
- height += 16;
-
- label = GuiCreateIllustrateLabel(container, _("To"));
- lv_obj_align(label, LV_ALIGN_TOP_LEFT, 24, height);
- lv_obj_set_style_text_color(label, WHITE_COLOR, LV_PART_MAIN);
- lv_obj_set_style_text_opa(label, LV_OPA_56, LV_PART_MAIN | LV_STATE_DEFAULT);
-
- height += 30;
-
- lv_obj_t *innerContainer;
-
- for (size_t i = 0; i < to->size; i++) {
- lv_obj_t *valueLabel, *indexLabel, *addressLabel;
- uint16_t innerHeight = 0;
- if (i > 0) {
- //add margin
- innerHeight += 16;
- }
- innerContainer = GuiCreateContainerWithParent(container, 360, innerHeight);
- lv_obj_set_style_bg_opa(innerContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
- lv_obj_align(innerContainer, LV_ALIGN_TOP_LEFT, 24, height);
-
- char *order = (char *)SRAM_MALLOC(5);
- snprintf_s(order, 5, "#%d", i + 1);
- indexLabel = GuiCreateIllustrateLabel(innerContainer, order);
- lv_obj_align(indexLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
-
- valueLabel = GuiCreateIllustrateLabel(innerContainer, to->data[i].value);
- lv_obj_set_style_text_color(valueLabel, ORANGE_COLOR, LV_PART_MAIN);
- lv_obj_align_to(valueLabel, indexLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
- if (to->data[i].is_change) {
- lv_obj_t *tagContainer = GuiCreateContainerWithParent(innerContainer, 87, 30);
- lv_obj_set_style_radius(tagContainer, 16, LV_PART_MAIN | LV_STATE_DEFAULT);
- lv_obj_set_style_bg_color(tagContainer, WHITE_COLOR, LV_PART_MAIN | LV_STATE_DEFAULT);
- lv_obj_set_style_bg_opa(tagContainer, 30, LV_PART_MAIN | LV_STATE_DEFAULT);
- lv_obj_t *tagLabel = lv_label_create(tagContainer);
-
- lv_label_set_text(tagLabel, "Change");
- lv_obj_set_style_text_font(tagLabel, g_defIllustrateFont, LV_PART_MAIN);
- lv_obj_set_style_text_color(tagLabel, WHITE_COLOR, LV_PART_MAIN);
- lv_obj_set_style_text_opa(tagLabel, 163, LV_PART_MAIN);
- lv_obj_align(tagLabel, LV_ALIGN_CENTER, 0, 0);
-
- lv_obj_align_to(tagContainer, valueLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
- }
- innerHeight += 30;
-
- addressLabel = GuiCreateIllustrateLabel(innerContainer, to->data[i].address);
- lv_obj_set_width(addressLabel, 360);
- lv_label_set_long_mode(addressLabel, LV_LABEL_LONG_WRAP);
- lv_obj_align(addressLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
- lv_obj_update_layout(addressLabel);
-
- innerHeight += lv_obj_get_height(addressLabel);
-
- if (to->data[i].memo != NULL && strnlen(to->data[i].memo, MAX_MEMO_LENGTH) > 0) {
- char *memo = (char *)SRAM_MALLOC(MAX_MEMO_LENGTH);
- snprintf_s(memo, MAX_MEMO_LENGTH, "Memo: %s", to->data[i].memo);
- lv_obj_t *memoLabel = GuiCreateIllustrateLabel(innerContainer, memo);
- lv_obj_align(memoLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
- lv_obj_set_style_text_color(memoLabel, WHITE_COLOR, LV_PART_MAIN);
- lv_obj_set_style_text_opa(memoLabel, LV_OPA_56, LV_PART_MAIN);
- lv_obj_update_layout(memoLabel);
-
- innerHeight += lv_obj_get_height(memoLabel);
- }
-
- lv_obj_set_height(innerContainer, innerHeight);
- lv_obj_update_layout(innerContainer);
-
- height += innerHeight;
- }
-
- // bottom padding
- height += 16;
-
- lv_obj_set_height(container, height);
- lv_obj_update_layout(container);
-
- return container;
-}
-
-PtrT_TransactionCheckResult GuiGetZcashCheckResult(void)
-{
- void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
- char ufvk[ZCASH_UFVK_MAX_LEN + 1] = {0};
- uint8_t sfp[32];
- GetZcashUFVK(GetCurrentAccountIndex(), ufvk, sfp);
- uint32_t zcash_account_index = 0;
- MnemonicType mnemonicType = GetMnemonicType();
- return check_zcash_tx(data, ufvk, sfp, zcash_account_index, mnemonicType == MNEMONIC_TYPE_SLIP39);
-}
-
-UREncodeResult *GuiGetZcashSignQrCodeData(void)
-{
- void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
- return SignInternal(sign_zcash_tx, data);
-}
-
-void FreeZcashMemory(void)
-{
- CHECK_FREE_UR_RESULT(g_urResult, false);
- CHECK_FREE_UR_RESULT(g_urMultiResult, true);
- CHECK_FREE_PARSE_RESULT(g_parseResult);
-}
\ No newline at end of file
diff --git a/src/ui/gui_chain/multi/cypherpunk/gui_zcash.h b/src/ui/gui_chain/multi/cypherpunk/gui_zcash.h
deleted file mode 100644
index ed3f807..0000000
--- a/src/ui/gui_chain/multi/cypherpunk/gui_zcash.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _GUI_ZCASH_H
-#define _GUI_ZCASH_H
-#include "rust.h"
-#include "gui.h"
-
-void GuiSetZcashUrData(URParseResult *urResult, URParseMultiResult *urMultiResult, bool multi);
-void *GuiGetZcashGUIData(void);
-PtrT_TransactionCheckResult GuiGetZcashCheckResult(void);
-UREncodeResult *GuiGetZcashSignQrCodeData(void);
-void FreeZcashMemory(void);
-
-void GuiZcashOverview(lv_obj_t *parent, void *totalData);
-
-#endif
\ No newline at end of file
diff --git a/src/ui/gui_chain/multi/gui_zcash.c b/src/ui/gui_chain/multi/gui_zcash.c
new file mode 100644
index 0000000..3e11e37
--- /dev/null
+++ b/src/ui/gui_chain/multi/gui_zcash.c
@@ -0,0 +1,323 @@
+#include "gui_zcash.h"
+#include "gui_chain_components.h"
+#include "user_memory.h"
+#include "account_manager.h"
+#include "gui_chain.h"
+#include "keystore.h"
+#include "screen_manager.h"
+#include "gui_chain.h"
+
+#define MAX_MEMO_LENGTH 1024
+
+static bool g_isMulti = false;
+static URParseResult *g_urResult = NULL;
+static URParseMultiResult *g_urMultiResult = NULL;
+static void *g_parseResult = NULL;
+static DisplayPczt *g_zcashData;
+
+#define CHECK_FREE_PARSE_RESULT(result) \
+ if (result != NULL) \
+ { \
+ free_TransactionParseResult_DisplayPczt((PtrT_TransactionParseResult_DisplayPczt)result); \
+ result = NULL; \
+ }
+
+void GuiSetZcashUrData(URParseResult *urResult, URParseMultiResult *urMultiResult, bool multi)
+{
+ g_urResult = urResult;
+ g_urMultiResult = urMultiResult;
+ g_isMulti = multi;
+}
+
+void *GuiGetZcashGUIData(void)
+{
+ CHECK_FREE_PARSE_RESULT(g_parseResult);
+ void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
+ char ufvk[ZCASH_UFVK_MAX_LEN] = {'\0'};
+ uint8_t sfp[32];
+ GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
+ GetZcashSFP(GetCurrentAccountIndex(), sfp);
+
+ PtrT_TransactionParseResult_DisplayPczt parseResult = NULL;
+ do {
+ parseResult = parse_zcash_tx(data, ufvk, sfp);
+ CHECK_CHAIN_BREAK(parseResult);
+ g_zcashData = parseResult->data;
+ g_parseResult = (void *)parseResult;
+
+ } while (0);
+ return g_parseResult;
+}
+
+static lv_obj_t* GuiZcashOverviewTransparent(lv_obj_t *parent, lv_obj_t *last_view);
+static lv_obj_t* GuiZcashOverviewOrchard(lv_obj_t *parent, lv_obj_t *last_view);
+static lv_obj_t* GuiZcashOverviewFrom(lv_obj_t *parent, VecFFI_DisplayFrom *from, lv_obj_t *last_view);
+static lv_obj_t* GuiZcashOverviewTo(lv_obj_t *parent, VecFFI_DisplayTo *to, lv_obj_t *last_view);
+
+void GuiZcashOverview(lv_obj_t *parent, void *totalData)
+{
+ lv_obj_set_size(parent, 408, 480);
+ lv_obj_add_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
+ lv_obj_add_flag(parent, LV_OBJ_FLAG_CLICKABLE);
+
+ lv_obj_t* container = GuiCreateContainerWithParent(parent, 408, 480);
+ lv_obj_add_flag(container, LV_OBJ_FLAG_SCROLLABLE);
+ lv_obj_add_flag(container, LV_OBJ_FLAG_CLICKABLE);
+
+ lv_obj_t* last_view = NULL;
+
+ if (g_zcashData->has_sapling) {
+ last_view = CreateTransactionItemView(container, _("Warning"), _("This transaction contains Sapling spends or outputs. Keystone does not support Sapling spend signing and output checking. Please take care of the potential risks."), last_view);
+ }
+
+ last_view = CreateTransactionItemView(container, _("Amount"), g_zcashData->total_transfer_value, last_view);
+ last_view = CreateTransactionItemView(container, _("Fee"), g_zcashData->fee_value, last_view);
+
+ if (g_zcashData->transparent != NULL) {
+ last_view = GuiZcashOverviewTransparent(container, last_view);
+ }
+
+ if (g_zcashData->orchard != NULL) {
+ last_view = GuiZcashOverviewOrchard(container, last_view);
+ }
+}
+
+static lv_obj_t* GuiZcashOverviewTransparent(lv_obj_t *parent, lv_obj_t *last_view)
+{
+ lv_obj_t* inner_last_view;
+ lv_obj_t* label = GuiCreateIllustrateLabel(parent, _("Transparent"));
+ lv_obj_align_to(label, last_view, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 24);
+
+ inner_last_view = label;
+
+ if (g_zcashData->transparent->from->size > 0) {
+ lv_obj_t* from_view = GuiZcashOverviewFrom(parent, g_zcashData->transparent->from, inner_last_view);
+ inner_last_view = from_view;
+ }
+
+ if (g_zcashData->transparent->to->size > 0) {
+ lv_obj_t* to_view = GuiZcashOverviewTo(parent, g_zcashData->transparent->to, inner_last_view);
+ inner_last_view = to_view;
+ }
+
+ return inner_last_view;
+}
+
+static lv_obj_t* GuiZcashOverviewOrchard(lv_obj_t* parent, lv_obj_t *last_view)
+{
+ lv_obj_t* inner_last_view;
+ lv_obj_t* label = GuiCreateIllustrateLabel(parent, _("Orchard"));
+ lv_obj_align_to(label, last_view, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 24);
+
+ inner_last_view = label;
+
+ if (g_zcashData->orchard->from->size > 0) {
+ lv_obj_t* from_view = GuiZcashOverviewFrom(parent, g_zcashData->orchard->from, inner_last_view);
+ inner_last_view = from_view;
+ }
+
+ if (g_zcashData->orchard->to->size > 0) {
+ lv_obj_t* to_view = GuiZcashOverviewTo(parent, g_zcashData->orchard->to, inner_last_view);
+ inner_last_view = to_view;
+ }
+
+ return inner_last_view;
+}
+
+static lv_obj_t* GuiZcashOverviewFrom(lv_obj_t *parent, VecFFI_DisplayFrom *from, lv_obj_t *last_view)
+{
+ lv_obj_t* label, *container;
+ uint16_t height = 0;
+
+ container = CreateTransactionContentContainer(parent, 408, height);
+ lv_obj_align_to(container, last_view, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 24);
+
+ // top padding
+ height += 16;
+
+ label = GuiCreateIllustrateLabel(container, _("From"));
+ lv_obj_align(label, LV_ALIGN_TOP_LEFT, 24, height);
+ lv_obj_set_style_text_color(label, WHITE_COLOR, LV_PART_MAIN);
+ lv_obj_set_style_text_opa(label, LV_OPA_56, LV_PART_MAIN | LV_STATE_DEFAULT);
+
+ height += 30;
+
+ lv_obj_t *innerContainer;
+
+ for (size_t i = 0; i < from->size; i++) {
+ lv_obj_t *valueLabel, *indexLabel, *addressLabel;
+ uint16_t innerHeight = 0;
+ if (i > 0) {
+ //add margin
+ innerHeight += 16;
+ }
+ innerContainer = GuiCreateContainerWithParent(container, 360, innerHeight);
+ lv_obj_set_style_bg_opa(innerContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
+ lv_obj_align(innerContainer, LV_ALIGN_TOP_LEFT, 24, height);
+
+ char *order = (char *)SRAM_MALLOC(5);
+ snprintf_s(order, 5, "#%d", i + 1);
+ indexLabel = GuiCreateIllustrateLabel(innerContainer, order);
+ lv_obj_align(indexLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
+
+ valueLabel = GuiCreateIllustrateLabel(innerContainer, from->data[i].value);
+ lv_obj_set_style_text_color(valueLabel, ORANGE_COLOR, LV_PART_MAIN);
+ lv_obj_align_to(valueLabel, indexLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
+
+ if (from->data[i].is_mine) {
+ lv_obj_t *tagContainer = GuiCreateContainerWithParent(innerContainer, 87, 30);
+ lv_obj_set_style_radius(tagContainer, 16, LV_PART_MAIN | LV_STATE_DEFAULT);
+ lv_obj_set_style_bg_color(tagContainer, WHITE_COLOR, LV_PART_MAIN | LV_STATE_DEFAULT);
+ lv_obj_set_style_bg_opa(tagContainer, 30, LV_PART_MAIN | LV_STATE_DEFAULT);
+ lv_obj_t *tagLabel = lv_label_create(tagContainer);
+ lv_label_set_text(tagLabel, "Mine");
+ lv_obj_set_style_text_font(tagLabel, g_defIllustrateFont, LV_PART_MAIN);
+ lv_obj_set_style_text_color(tagLabel, WHITE_COLOR, LV_PART_MAIN);
+ lv_obj_set_style_text_opa(tagLabel, 163, LV_PART_MAIN);
+ lv_obj_align(tagLabel, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_align_to(tagContainer, valueLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
+ }
+
+ innerHeight += 30;
+
+ addressLabel = GuiCreateIllustrateLabel(innerContainer, from->data[i].address);
+ lv_obj_set_width(addressLabel, 360);
+ lv_label_set_long_mode(addressLabel, LV_LABEL_LONG_WRAP);
+ lv_obj_align(addressLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
+ lv_obj_update_layout(addressLabel);
+
+ innerHeight += lv_obj_get_height(addressLabel);
+
+ lv_obj_set_height(innerContainer, innerHeight);
+ lv_obj_update_layout(innerContainer);
+
+ height += innerHeight;
+ }
+
+ // bottom padding
+ height += 16;
+
+ lv_obj_set_height(container, height);
+ lv_obj_update_layout(container);
+
+ return container;
+}
+
+static lv_obj_t* GuiZcashOverviewTo(lv_obj_t *parent, VecFFI_DisplayTo *to, lv_obj_t *last_view)
+{
+ lv_obj_t* label, *container;
+ uint16_t height = 0;
+
+ container = CreateTransactionContentContainer(parent, 408, height);
+ lv_obj_add_flag(container, LV_OBJ_FLAG_SCROLLABLE);
+ lv_obj_add_flag(container, LV_OBJ_FLAG_CLICKABLE);
+ lv_obj_align_to(container, last_view, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 24);
+
+ // top padding
+ height += 16;
+
+ label = GuiCreateIllustrateLabel(container, _("To"));
+ lv_obj_align(label, LV_ALIGN_TOP_LEFT, 24, height);
+ lv_obj_set_style_text_color(label, WHITE_COLOR, LV_PART_MAIN);
+ lv_obj_set_style_text_opa(label, LV_OPA_56, LV_PART_MAIN | LV_STATE_DEFAULT);
+
+ height += 30;
+
+ lv_obj_t *innerContainer;
+
+ for (size_t i = 0; i < to->size; i++) {
+ lv_obj_t *valueLabel, *indexLabel, *addressLabel;
+ uint16_t innerHeight = 0;
+ if (i > 0) {
+ //add margin
+ innerHeight += 16;
+ }
+ innerContainer = GuiCreateContainerWithParent(container, 360, innerHeight);
+ lv_obj_set_style_bg_opa(innerContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
+ lv_obj_align(innerContainer, LV_ALIGN_TOP_LEFT, 24, height);
+
+ char *order = (char *)SRAM_MALLOC(5);
+ snprintf_s(order, 5, "#%d", i + 1);
+ indexLabel = GuiCreateIllustrateLabel(innerContainer, order);
+ lv_obj_align(indexLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
+
+ valueLabel = GuiCreateIllustrateLabel(innerContainer, to->data[i].value);
+ lv_obj_set_style_text_color(valueLabel, ORANGE_COLOR, LV_PART_MAIN);
+ lv_obj_align_to(valueLabel, indexLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
+ if (to->data[i].is_change) {
+ lv_obj_t *tagContainer = GuiCreateContainerWithParent(innerContainer, 87, 30);
+ lv_obj_set_style_radius(tagContainer, 16, LV_PART_MAIN | LV_STATE_DEFAULT);
+ lv_obj_set_style_bg_color(tagContainer, WHITE_COLOR, LV_PART_MAIN | LV_STATE_DEFAULT);
+ lv_obj_set_style_bg_opa(tagContainer, 30, LV_PART_MAIN | LV_STATE_DEFAULT);
+ lv_obj_t *tagLabel = lv_label_create(tagContainer);
+
+ lv_label_set_text(tagLabel, "Change");
+ lv_obj_set_style_text_font(tagLabel, g_defIllustrateFont, LV_PART_MAIN);
+ lv_obj_set_style_text_color(tagLabel, WHITE_COLOR, LV_PART_MAIN);
+ lv_obj_set_style_text_opa(tagLabel, 163, LV_PART_MAIN);
+ lv_obj_align(tagLabel, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_align_to(tagContainer, valueLabel, LV_ALIGN_OUT_RIGHT_MID, 16, 0);
+ }
+ innerHeight += 30;
+
+ addressLabel = GuiCreateIllustrateLabel(innerContainer, to->data[i].address);
+ lv_obj_set_width(addressLabel, 360);
+ lv_label_set_long_mode(addressLabel, LV_LABEL_LONG_WRAP);
+ lv_obj_align(addressLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
+ lv_obj_update_layout(addressLabel);
+
+ innerHeight += lv_obj_get_height(addressLabel);
+
+ if (to->data[i].memo != NULL && strnlen(to->data[i].memo, MAX_MEMO_LENGTH) > 0) {
+ char *memo = (char *)SRAM_MALLOC(MAX_MEMO_LENGTH);
+ snprintf_s(memo, MAX_MEMO_LENGTH, "Memo: %s", to->data[i].memo);
+ lv_obj_t *memoLabel = GuiCreateIllustrateLabel(innerContainer, memo);
+ lv_obj_align(memoLabel, LV_ALIGN_TOP_LEFT, 0, innerHeight);
+ lv_obj_set_style_text_color(memoLabel, WHITE_COLOR, LV_PART_MAIN);
+ lv_obj_set_style_text_opa(memoLabel, LV_OPA_56, LV_PART_MAIN);
+ lv_obj_update_layout(memoLabel);
+
+ innerHeight += lv_obj_get_height(memoLabel);
+ }
+
+ lv_obj_set_height(innerContainer, innerHeight);
+ lv_obj_update_layout(innerContainer);
+
+ height += innerHeight;
+ }
+
+ // bottom padding
+ height += 16;
+
+ lv_obj_set_height(container, height);
+ lv_obj_update_layout(container);
+
+ return container;
+}
+
+PtrT_TransactionCheckResult GuiGetZcashCheckResult(void)
+{
+ void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
+ char ufvk[ZCASH_UFVK_MAX_LEN + 1] = {0};
+ uint8_t sfp[32];
+ GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
+ GetZcashSFP(GetCurrentAccountIndex(), sfp);
+ uint32_t zcash_account_index = 0;
+ MnemonicType mnemonicType = GetMnemonicType();
+ return check_zcash_tx(data, ufvk, sfp, zcash_account_index, mnemonicType == MNEMONIC_TYPE_SLIP39);
+}
+
+UREncodeResult *GuiGetZcashSignQrCodeData(void)
+{
+ void *data = g_isMulti ? g_urMultiResult->data : g_urResult->data;
+ return SignInternal(sign_zcash_tx, data);
+}
+
+void FreeZcashMemory(void)
+{
+ CHECK_FREE_UR_RESULT(g_urResult, false);
+ CHECK_FREE_UR_RESULT(g_urMultiResult, true);
+ CHECK_FREE_PARSE_RESULT(g_parseResult);
+}
\ No newline at end of file
diff --git a/src/ui/gui_chain/multi/gui_zcash.h b/src/ui/gui_chain/multi/gui_zcash.h
new file mode 100644
index 0000000..ed3f807
--- /dev/null
+++ b/src/ui/gui_chain/multi/gui_zcash.h
@@ -0,0 +1,14 @@
+#ifndef _GUI_ZCASH_H
+#define _GUI_ZCASH_H
+#include "rust.h"
+#include "gui.h"
+
+void GuiSetZcashUrData(URParseResult *urResult, URParseMultiResult *urMultiResult, bool multi);
+void *GuiGetZcashGUIData(void);
+PtrT_TransactionCheckResult GuiGetZcashCheckResult(void);
+UREncodeResult *GuiGetZcashSignQrCodeData(void);
+void FreeZcashMemory(void);
+
+void GuiZcashOverview(lv_obj_t *parent, void *totalData);
+
+#endif
\ No newline at end of file
diff --git a/src/ui/gui_wallet/multi/web3/gui_wallet.c b/src/ui/gui_wallet/multi/web3/gui_wallet.c
index 00a90a1..fbc6226 100644
--- a/src/ui/gui_wallet/multi/web3/gui_wallet.c
+++ b/src/ui/gui_wallet/multi/web3/gui_wallet.c
@@ -482,7 +482,11 @@ UREncodeResult *GuiGetKeystoneConnectWalletData(void)
GetSerialNumber(serialNumber);
char firmwareVersion[12];
GetSoftWareVersionNumber(firmwareVersion);
- UREncodeResult *urEncode = get_keystone_connect_wallet_ur(mfp, sizeof(mfp), serialNumber, public_keys, "Keystone 3 Pro", firmwareVersion);
+
+ uint8_t sfp[32];
+ GetZcashSFP(GetCurrentAccountIndex(), sfp);
+
+ UREncodeResult *urEncode = get_keystone_connect_wallet_ur(mfp, sizeof(mfp), serialNumber, public_keys, "Keystone 3 Pro", firmwareVersion, sfp, sizeof(sfp));
CHECK_CHAIN_PRINT(urEncode);
SRAM_FREE(public_keys);
return urEncode;
diff --git a/src/ui/gui_widgets/multi/cypherpunk/gui_connect_wallet_widgets.c b/src/ui/gui_widgets/multi/cypherpunk/gui_connect_wallet_widgets.c
index 1dfd2d5..195bcef 100644
--- a/src/ui/gui_widgets/multi/cypherpunk/gui_connect_wallet_widgets.c
+++ b/src/ui/gui_widgets/multi/cypherpunk/gui_connect_wallet_widgets.c
@@ -353,15 +353,14 @@ void GuiConnectWalletInit(void)
UREncodeResult *GuiGetZecData(void)
{
- uint8_t mfp[4];
- GetMasterFingerPrint(mfp);
CSliceFFI_ZcashKey *keys = SRAM_MALLOC(sizeof(CSliceFFI_ZcashKey));
ZcashKey data[1];
keys->data = data;
keys->size = 1;
char ufvk[384] = {'\0'};
uint8_t sfp[32];
- GetZcashUFVK(GetCurrentAccountIndex(), ufvk, sfp);
+ GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
+ GetZcashSFP(GetCurrentAccountIndex(), sfp);
data[0].key_text = ufvk;
data[0].key_name = GetWalletName();
data[0].index = 0;
diff --git a/src/ui/gui_widgets/multi/gui_standard_receive_widgets.c b/src/ui/gui_widgets/multi/gui_standard_receive_widgets.c
index 7a33187..c4a0452 100644
--- a/src/ui/gui_widgets/multi/gui_standard_receive_widgets.c
+++ b/src/ui/gui_widgets/multi/gui_standard_receive_widgets.c
@@ -918,8 +918,8 @@ static void ModelGetAddress(uint32_t index, AddressDataItem_t *item)
#ifdef CYPHERPUNK_VERSION
if (g_chainCard == HOME_WALLET_CARD_ZEC) {
char ufvk[ZCASH_UFVK_MAX_LEN] = {'\0'};
- uint8_t sfp[32];
- GetZcashUFVK(GetCurrentAccountIndex(), ufvk, sfp);
+ GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
+
result = generate_zcash_default_address(ufvk);
}
#endif
@@ -1084,8 +1084,6 @@ void GuiResetAllStandardAddressIndex(void)
memset_s(g_thorChainSelectIndex, sizeof(g_thorChainSelectIndex), 0, sizeof(g_thorChainSelectIndex));
}
-
-
static void SetCurrentSelectIndex(uint32_t selectIndex)
{
#ifdef WEB3_VERSION
Why this scored 24/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.