Browse Source

Add support for mainnet

taddr
Aditya Kulkarni 5 years ago
parent
commit
e25484aeb0
  1. 6
      cli/src/main.rs
  2. 31
      lib/src/paper.rs
  3. 15
      lib/src/pdf.rs

6
cli/src/main.rs

@ -41,11 +41,7 @@ fn main() {
.get_matches();
let testnet: bool = matches.is_present("testnet");
if !testnet {
eprintln!("Mainnet addresses are not supported yet. Please re-run with --testnet");
return;
}
let filename = matches.value_of("output");
let format = matches.value_of("format").unwrap();

31
lib/src/paper.rs

@ -15,6 +15,12 @@ pub fn generate_wallet(testnet: bool, count: u32) -> String {
return gen_addresses_with_seed_as_json(testnet, count, &seed);
}
/**
* Generate `count` addresses with the given seed. The addresses are derived from m/32'/cointype'/index' where
* index is 0..count
*
* Note that cointype is 1 for testnet and 133 for mainnet
*/
fn gen_addresses_with_seed_as_json(testnet: bool, count: u32, seed: &[u8]) -> String {
let mut ans = array![];
@ -32,7 +38,7 @@ fn gen_addresses_with_seed_as_json(testnet: bool, count: u32, seed: &[u8]) -> St
}
// Generate a standard ZIP-32 address from the given seed at 32'/44'/0'/index
fn get_address(testnet: bool, seed: &[u8], index: u32) -> (String, String, String) {
fn get_address(testnet: bool, seed: &[u8], index: u32) -> (String, String, json::JsonValue) {
let addr_prefix = if testnet {"ztestsapling"} else {"zs"};
let pk_prefix = if testnet {"secret-extended-key-test"} else {"secret-extended-key-main"};
let cointype = if testnet {1} else {133};
@ -45,7 +51,10 @@ fn get_address(testnet: bool, seed: &[u8], index: u32) -> (String, String, Strin
ChildIndex::Hardened(index)
],
);
let path = format!("HDSeed: {}, Path: m/32'/{}'/{}'", hex::encode(seed), cointype, index);
let path = object!{
"HDSeed" => hex::encode(seed),
"path" => format!("m/32'/{}'/{}'", cointype, index)
};
let (_d, addr) = spk.default_address().expect("Cannot get result");
@ -66,9 +75,17 @@ fn get_address(testnet: bool, seed: &[u8], index: u32) -> (String, String, Strin
}
// Tests
#[cfg(test)]
mod tests {
/**
* Test the wallet generation and that it is generating the right number and type of addresses
*/
#[test]
fn test_wallet_generation() {
use crate::paper::generate_wallet;
@ -80,7 +97,7 @@ mod tests {
assert_eq!(j.len(), 1);
assert!(j[0]["address"].as_str().unwrap().starts_with("ztestsapling"));
assert!(j[0]["private_key"].as_str().unwrap().starts_with("secret-extended-key-test"));
assert!(j[0]["seed"].as_str().unwrap().contains("32'/1'/0'"));
assert_eq!(j[0]["seed"]["path"].as_str().unwrap(), "m/32'/1'/0'");
// Mainnet wallet
@ -89,7 +106,7 @@ mod tests {
assert_eq!(j.len(), 1);
assert!(j[0]["address"].as_str().unwrap().starts_with("zs"));
assert!(j[0]["private_key"].as_str().unwrap().starts_with("secret-extended-key-main"));
assert!(j[0]["seed"].as_str().unwrap().contains("32'/133'/0'"));
assert_eq!(j[0]["seed"]["path"].as_str().unwrap(), "m/32'/133'/0'");
// Check if all the addresses are the same
let w = generate_wallet(true, 3);
@ -98,7 +115,7 @@ mod tests {
let mut s = HashSet::new();
for i in 0..3 {
assert!(j[i]["address"].as_str().unwrap().starts_with("ztestsapling"));
assert!(j[i]["seed"].as_str().unwrap().contains(format!("32'/1'/{}'", i).as_str()));
assert_eq!(j[i]["seed"]["path"].as_str().unwrap(), format!("m/32'/1'/{}'", i).as_str());
s.insert(j[i]["address"].as_str().unwrap());
s.insert(j[i]["private_key"].as_str().unwrap());
@ -107,7 +124,7 @@ mod tests {
assert_eq!(s.len(), 6);
}
// Test the address derivation against the test data.
// Test the address derivation against the test data (see below)
fn test_address_derivation(testdata: &str, testnet: bool) {
use crate::paper::gen_addresses_with_seed_as_json;
let td = json::parse(&testdata.replace("'", "\"")).unwrap();
@ -116,7 +133,7 @@ mod tests {
let seed = hex::decode(i["seed"].as_str().unwrap()).unwrap();
let num = i["num"].as_u32().unwrap();
let addresses = gen_addresses_with_seed_as_json(testnet, num+1, &seed[0..32]);
let addresses = gen_addresses_with_seed_as_json(testnet, num+1, &seed[..]);
let j = json::parse(&addresses).unwrap();
assert_eq!(j[num as usize]["address"], i["addr"]);

15
lib/src/pdf.rs

@ -41,7 +41,7 @@ pub fn save_to_pdf(addresses: &str, filename: &str) {
// Add address + private key
add_address_to_page(&current_layer, &font, &font_bold, kv["address"].as_str().unwrap(), pos);
add_pk_to_page(&current_layer, &font, &font_bold, kv["private_key"].as_str().unwrap(), kv["seed"].as_str().unwrap(), pos);
add_pk_to_page(&current_layer, &font, &font_bold, kv["private_key"].as_str().unwrap(), kv["seed"]["HDSeed"].as_str().unwrap(), kv["seed"]["path"].as_str().unwrap(), pos);
// Is the shape stroked? Is the shape closed? Is the shape filled?
let line1 = Line {
@ -119,8 +119,8 @@ fn add_address_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef
let ypos = 297.0 - 5.0 - 50.0 - (140.0 * pos as f64);
add_qrcode_image_to_page(current_layer, scaledimg, finalsize, Mm(10.0), Mm(ypos));
current_layer.use_text("Address", 14, Mm(55.0), Mm(ypos+27.5), &font_bold);
let strs = split_to_max(&address, 44, 8);
current_layer.use_text("ZEC Address (Sapling)", 14, Mm(55.0), Mm(ypos+27.5), &font_bold);
let strs = split_to_max(&address, 39, 6);
for i in 0..strs.len() {
current_layer.use_text(strs[i].clone(), 12, Mm(55.0), Mm(ypos+15.0-((i*5) as f64)), &font);
}
@ -129,21 +129,22 @@ fn add_address_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef
/**
* Add the private key section to the PDF at `pos`, which can effectively be only 0 or 1.
*/
fn add_pk_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef, font_bold: &IndirectFontRef, pk: &str, seed: &str, pos: u32) {
fn add_pk_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef, font_bold: &IndirectFontRef, pk: &str, seed: &str, path: &str, pos: u32) {
let (scaledimg, finalsize) = qrcode_scaled(pk, 10);
// page_height top_margin vertical_padding position
let ypos = 297.0 - 5.0 - 100.0 - (140.0 * pos as f64);
add_qrcode_image_to_page(current_layer, scaledimg, finalsize, Mm(145.0), Mm(ypos-17.5));
current_layer.use_text("Private Key", 14, Mm(10.0), Mm(ypos+27.5), &font_bold);
current_layer.use_text("Private Key", 14, Mm(10.0), Mm(ypos+32.5), &font_bold);
let strs = split_to_max(&pk, 45, 10);
for i in 0..strs.len() {
current_layer.use_text(strs[i].clone(), 12, Mm(10.0), Mm(ypos+15.0-((i*5) as f64)), &font);
current_layer.use_text(strs[i].clone(), 12, Mm(10.0), Mm(ypos+25.0-((i*5) as f64)), &font);
}
// And add the seed too.
current_layer.use_text(seed, 8, Mm(10.0), Mm(ypos-25.0), &font);
current_layer.use_text(format!("HDSeed: {}, Path: {}", seed, path).as_str(), 8, Mm(10.0), Mm(ypos-25.0), &font);
}
/**

Loading…
Cancel
Save