Skip to content

Commit 4d593a4

Browse files
committed
feat: zcash connect wallet
1 parent 17c39a3 commit 4d593a4

File tree

14 files changed

+519
-39
lines changed

14 files changed

+519
-39
lines changed

rust/apps/wallets/Cargo.lock

+311-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/apps/wallets/rust-toolchain

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2023-06-26
1+
nightly

rust/apps/wallets/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub mod solana;
2626
pub mod sui;
2727
pub mod thor_wallet;
2828
pub mod tonkeeper;
29+
pub mod zcash;
2930
mod utils;
3031
pub mod xbull;
3132
pub mod xrp_toolkit;

rust/apps/wallets/src/zcash.rs

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use alloc::string::{String, ToString};
2+
use alloc::vec;
3+
use alloc::vec::Vec;
4+
5+
use app_utils::impl_public_struct;
6+
use keystore::algorithms::zcash::vendor::{
7+
zcash_keys::keys::UnifiedFullViewingKey, zcash_protocol::consensus::MainNetwork,
8+
};
9+
use third_party::ur_registry::{
10+
crypto_hd_key::CryptoHDKey,
11+
crypto_key_path::CryptoKeyPath,
12+
error::{URError, URResult},
13+
zcash::{
14+
zcash_accounts::ZcashAccounts, zcash_full_viewing_key::ZcashFullViewingKey,
15+
zcash_unified_full_viewing_key::ZcashUnifiedFullViewingKey,
16+
},
17+
};
18+
19+
impl_public_struct!(UFVKInfo {
20+
key_text: String,
21+
key_name: String,
22+
transparent_key_path: String,
23+
orchard_key_path: String
24+
});
25+
26+
pub fn generate_sync_ur(key_infos: Vec<UFVKInfo>, mfp: [u8; 4]) -> URResult<ZcashAccounts> {
27+
let keys = key_infos
28+
.iter()
29+
.map(|info| {
30+
let ufvk = UnifiedFullViewingKey::decode(&MainNetwork, &info.key_text)
31+
.map_err(|e| URError::UrEncodeError(e.to_string()))?;
32+
33+
let transprant = ufvk.transparent().and_then(|v| Some(v.serialize()));
34+
let orchard = ufvk
35+
.orchard()
36+
.and_then(|v| Some(v.to_bytes()))
37+
.ok_or(URError::UrEncodeError(format!("Zcash missing orchard fvk")))?;
38+
39+
let transparent_key = transprant
40+
.map(|v| {
41+
let (chaincode, pubkey) = v.split_at(32);
42+
let keypath = CryptoKeyPath::from_path(info.transparent_key_path.clone(), None)
43+
.map_err(|e| URError::UrEncodeError(e))?;
44+
Ok(CryptoHDKey::new_extended_key(
45+
None,
46+
pubkey.to_vec(),
47+
Some(chaincode.to_vec()),
48+
None,
49+
Some(keypath),
50+
None,
51+
None,
52+
None,
53+
None,
54+
))
55+
})
56+
.transpose()?;
57+
58+
let keypath = CryptoKeyPath::from_path(info.orchard_key_path.clone(), None)
59+
.map_err(|e| URError::UrEncodeError(e))?;
60+
61+
let orchard_key = ZcashFullViewingKey::new(keypath, orchard.to_vec());
62+
63+
Ok(ZcashUnifiedFullViewingKey::new(
64+
transparent_key,
65+
orchard_key,
66+
Some(info.key_name.clone()),
67+
))
68+
})
69+
.collect::<URResult<Vec<ZcashUnifiedFullViewingKey>>>()?;
70+
let accounts = ZcashAccounts::new(mfp, keys);
71+
Ok(accounts)
72+
}

rust/docs/README.md

Whitespace-only changes.

rust/keystore/Cargo.lock

+21-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/rust_c/Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/rust_c/src/common/src/structs.rs

+28
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,31 @@ impl Free for PtrT<ExtendedPublicKey> {
190190
}
191191
}
192192
}
193+
194+
#[repr(C)]
195+
pub struct ZcashKey {
196+
pub key_text: PtrString,
197+
pub key_name: PtrString,
198+
pub transparent_key_path: PtrString,
199+
pub orchard_key_path: PtrString,
200+
}
201+
202+
impl_c_ptr!(ZcashKey);
203+
204+
impl Free for ZcashKey {
205+
fn free(&self) {
206+
free_str_ptr!(self.key_text);
207+
free_str_ptr!(self.key_name);
208+
free_str_ptr!(self.transparent_key_path);
209+
free_str_ptr!(self.orchard_key_path);
210+
}
211+
}
212+
213+
impl Free for PtrT<ZcashKey> {
214+
fn free(&self) {
215+
unsafe {
216+
let x = Box::from_raw(*self);
217+
x.free()
218+
}
219+
}
220+
}

rust/rust_c/src/wallet/src/multi_coins_wallet/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub mod tonkeeper;
1616
mod utils;
1717
pub mod xbull;
1818
pub mod xrp_toolkit;
19+
pub mod zcash;
1920

2021
pub mod thor_wallet;
2122

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use alloc::string::ToString;
2+
use alloc::vec::Vec;
3+
use alloc::{format, slice};
4+
use app_wallets::zcash::{generate_sync_ur, UFVKInfo};
5+
use common_rust_c::extract_array;
6+
use common_rust_c::ffi::CSliceFFI;
7+
use common_rust_c::structs::ZcashKey;
8+
use common_rust_c::types::{Ptr, PtrBytes, PtrString};
9+
use common_rust_c::ur::{UREncodeResult, FRAGMENT_MAX_LENGTH_DEFAULT};
10+
use common_rust_c::utils::{recover_c_array, recover_c_char};
11+
use third_party::ur_registry::bytes::Bytes;
12+
use third_party::ur_registry::error::URError;
13+
use third_party::ur_registry::traits::RegistryItem;
14+
use third_party::ur_registry::zcash::zcash_accounts::ZcashAccounts;
15+
16+
#[no_mangle]
17+
pub extern "C" fn get_connect_zcash_wallet_ur(
18+
mfp: PtrBytes,
19+
mfp_len: u32,
20+
zcash_keys: Ptr<CSliceFFI<ZcashKey>>,
21+
) -> *mut UREncodeResult {
22+
if mfp_len != 4 {
23+
return UREncodeResult::from(URError::UrEncodeError(format!(
24+
"master fingerprint length must be 4, current is {}",
25+
mfp_len
26+
)))
27+
.c_ptr();
28+
}
29+
let mfp = extract_array!(mfp, u8, mfp_len);
30+
let mfp = match <[u8; 4]>::try_from(mfp) {
31+
Ok(mfp) => mfp,
32+
Err(e) => return UREncodeResult::from(URError::UrEncodeError(e.to_string())).c_ptr(),
33+
};
34+
unsafe {
35+
let keys = recover_c_array(zcash_keys);
36+
let ufvks: Vec<UFVKInfo> = keys
37+
.iter()
38+
.map(|v| {
39+
UFVKInfo::new(
40+
recover_c_char(v.key_text),
41+
recover_c_char(v.key_name),
42+
recover_c_char(v.transparent_key_path),
43+
recover_c_char(v.orchard_key_path),
44+
)
45+
})
46+
.collect();
47+
let result = generate_sync_ur(ufvks, mfp);
48+
match result.map(|v| v.try_into()) {
49+
Ok(v) => match v {
50+
Ok(data) => UREncodeResult::encode(
51+
data,
52+
ZcashAccounts::get_registry_type().get_type(),
53+
FRAGMENT_MAX_LENGTH_DEFAULT,
54+
)
55+
.c_ptr(),
56+
Err(e) => UREncodeResult::from(e).c_ptr(),
57+
},
58+
Err(e) => UREncodeResult::from(e).c_ptr(),
59+
}
60+
}
61+
}

rust/third_party/Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/third_party/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ rsa = { version = "0.8.2", default-features = false }
2020
sha1 = { version = "0.10.5", default-features = false }
2121
cty = "0.2.2"
2222
cstr_core = "0.2.6"
23-
ur-registry = { git = "https://[email protected]/KeystoneHQ/keystone-sdk-rust.git", tag = "0.0.32" }
24-
ur-parse-lib = { git = "https://[email protected]/KeystoneHQ/keystone-sdk-rust.git", tag = "0.0.32" }
23+
ur-registry = { git = "https://[email protected]/KeystoneHQ/keystone-sdk-rust.git", tag = "0.0.33-alpha1" }
24+
ur-parse-lib = { git = "https://[email protected]/KeystoneHQ/keystone-sdk-rust.git", tag = "0.0.33-alpha1" }
2525
ed25519-bip32-core = { version = "0.1.1", default-features = false }
2626
cryptoxide = "0.4"
2727
itertools = { version = "0.10.5", default-features = false, features = [

src/ui/gui_components/gui_status_bar.c

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ const static CoinWalletInfo_t g_walletBtn[] = {
104104
{WALLET_LIST_TYPHON, "Typhon Wallet", &walletTyphon},
105105
{WALLET_LIST_BLUE, "BlueWallet", &walletBluewallet},
106106
{WALLET_LIST_SUB, "SubWallet", &walletSubwallet},
107+
{WALLET_LIST_ZASHI, "Zashi", &walletZashi},
107108
{WALLET_LIST_SOLFARE, "Solflare", &walletSolflare},
108109
{WALLET_LIST_BACKPACK, "Backpack", &walletBackpack},
109110
{WALLET_LIST_RABBY, "Rabby", &walletRabby},

src/ui/gui_widgets/gui_connect_wallet_widgets.c

+16-17
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,6 @@ static void GuiInitWalletListArray()
349349
}
350350
}
351351

352-
353352
// static void GuiInitWalletListArray()
354353
// {
355354
// SetWalletListEnable(true);
@@ -457,7 +456,6 @@ static void OpenQRCodeHandler(lv_event_t *e)
457456
GuiEmitSignal(SIG_SETUP_VIEW_TILE_NEXT, NULL, 0);
458457
}
459458

460-
461459
#ifndef BTC_ONLY
462460
void GuiConnectWalletPasswordErrorCount(void *param)
463461
{
@@ -869,7 +867,6 @@ static void AddKeystoneWalletCoins(void)
869867
lv_obj_align(img, LV_ALIGN_TOP_LEFT, 132, 2);
870868
}
871869

872-
873870
static void AddBlueWalletCoins(void)
874871
{
875872
if (lv_obj_get_child_cnt(g_coinCont) > 0) {
@@ -998,7 +995,6 @@ static void AddThorWalletCoins(void)
998995
}
999996
}
1000997

1001-
1002998
static void AddNightlyCoins(void)
1003999
{
10041000
if (lv_obj_get_child_cnt(g_coinCont) > 0) {
@@ -1013,8 +1009,6 @@ static void AddNightlyCoins(void)
10131009
}
10141010
}
10151011

1016-
1017-
10181012
static void AddChainAddress(void)
10191013
{
10201014
if (lv_obj_get_child_cnt(g_bottomCont) > 0) {
@@ -1181,7 +1175,6 @@ UREncodeResult *GuiGetKeplrData(void)
11811175
return GuiGetKeplrDataByIndex(GetConnectWalletAccountIndex(GetWalletNameByIndex(g_connectWalletTileView.walletIndex)));
11821176
}
11831177

1184-
11851178
UREncodeResult *GuiGetADAData(void)
11861179
{
11871180
return GuiGetADADataByIndex(GetWalletNameByIndex(g_connectWalletTileView.walletIndex));
@@ -1210,14 +1203,21 @@ UREncodeResult *GuiGetTonData(void)
12101203

12111204
UREncodeResult *GuiGetZecData(void)
12121205
{
1213-
uint8_t* mfp = NULL;
1214-
char* path = NULL;
1215-
char* xpub;
1216-
char* walletName = GetWalletName();
1217-
if (walletName == NULL) {
1218-
walletName = "Keystone";
1219-
}
1220-
return get_tonkeeper_wallet_ur(xpub, walletName, mfp, mfp == NULL ? 0 : 4, path);
1206+
uint8_t mfp[4];
1207+
GetMasterFingerPrint(mfp);
1208+
CSliceFFI_ZcashKey *keys = SRAM_MALLOC(sizeof(CSliceFFI_ZcashKey));
1209+
ZcashKey data[1];
1210+
keys->data = data;
1211+
keys->size = 1;
1212+
char ufvk[384] = {'\0'};
1213+
GetZcashUFVK(GetCurrentAccountIndex(), ufvk);
1214+
data[0].key_text = ufvk;
1215+
data[0].key_name = GetWalletName();
1216+
char transparent_path[24] = "m/44'/133'/0'";
1217+
char orchard_path[24] = "m/32'/133'/0'";
1218+
data[0].transparent_key_path = transparent_path;
1219+
data[0].orchard_key_path = orchard_path;
1220+
return get_connect_zcash_wallet_ur(mfp, mfp == NULL ? 0 : 4, keys);
12211221
}
12221222

12231223
void GuiPrepareArConnectWalletView(void)
@@ -1346,7 +1346,7 @@ void GuiConnectWalletSetQrdata(WALLET_LIST_INDEX_ENUM index)
13461346
AddTonCoins();
13471347
break;
13481348
case WALLET_LIST_ZASHI:
1349-
func = GuiGetTonData;
1349+
func = GuiGetZecData;
13501350
AddZecCoins();
13511351
break;
13521352
case WALLET_LIST_KEYSTONE:
@@ -1996,7 +1996,6 @@ int8_t GuiConnectWalletNextTile(void)
19961996
return SUCCESS_CODE;
19971997
}
19981998

1999-
20001999
int8_t GuiConnectWalletPrevTile(void)
20012000
{
20022001
switch (g_connectWalletTileView.currentTile) {

0 commit comments

Comments
 (0)