Browse Source

Multiple address support

taddr
Aditya Kulkarni 5 years ago
parent
commit
dcf8e31944
  1. 10
      cli/src/main.rs
  2. 8
      lib/src/paper.rs
  3. 56
      lib/src/pdf.rs

10
cli/src/main.rs

@ -26,10 +26,10 @@ fn main() {
.long("output")
.index(1)
.help("Name of output file."))
.arg(Arg::with_name("num_addresses")
.short("n")
.long("num_addresses")
.help("Number of addresses to generate")
.arg(Arg::with_name("z_addresses")
.short("z")
.long("z_addresses")
.help("Number of Z addresses (sapling) to generate")
.takes_value(true)
.default_value("1")
.validator(|i:String| match i.parse::<i32>() {
@ -44,7 +44,7 @@ fn main() {
return;
}
let num_addresses = matches.value_of("num_addresses").unwrap().parse::<u32>().unwrap();
let num_addresses = matches.value_of("z_addresses").unwrap().parse::<u32>().unwrap();
let addresses = generate_wallet(testnet, num_addresses);
println!("{}", addresses);
pdf::save_to_pdf(&addresses, "test_working.pdf");

8
lib/src/paper.rs

@ -19,18 +19,19 @@ fn gen_addresses_with_seed_as_json(testnet: bool, count: u32, seed: &[u8; 32]) -
let mut ans = array![];
for i in 0..count {
let (addr, pk) = get_address(testnet, &seed);
let (addr, pk) = get_address(testnet, &seed, i);
ans.push(object!{
"num" => i,
"address" => addr,
"private_key" => pk
"private_key" => pk,
"seed" => format!("HDSeed: {}, Path: 32'/44'/0'/{}", hex::encode(seed), i)
}).unwrap();
}
return json::stringify_pretty(ans, 2);
}
fn get_address(testnet: bool, seed: &[u8; 32]) -> (String, String) {
fn get_address(testnet: bool, seed: &[u8; 32], index: u32) -> (String, String) {
let addr_prefix = if testnet {"ztestsapling"} else {"zs"};
let pk_prefix = if testnet {"secret-extended-key-test"} else {"secret-extended-key-main"};
@ -40,6 +41,7 @@ fn get_address(testnet: bool, seed: &[u8; 32]) -> (String, String) {
ChildIndex::Hardened(32),
ChildIndex::Hardened(44),
ChildIndex::Hardened(0),
ChildIndex::from_index(index)
],
);

56
lib/src/pdf.rs

@ -5,6 +5,7 @@ use qrcode::types::Color;
use std::io::BufWriter;
use std::convert::From;
use std::f64;
use std::fs::File;
use printpdf::*;
@ -13,15 +14,34 @@ use printpdf::*;
*/
pub fn save_to_pdf(addresses: &str, filename: &str) {
let (doc, page1, layer1) = PdfDocument::new("Zec Sapling Paper Wallet", Mm(210.0), Mm(297.0), "Layer 1");
let current_layer = doc.get_page(page1).get_layer(layer1);
let font = doc.add_builtin_font(BuiltinFont::Courier).unwrap();
let font_bold = doc.add_builtin_font(BuiltinFont::CourierBold).unwrap();
let keys = json::parse(&addresses).unwrap();
// Position on the PDF page.
let mut pos = 0;
let mut current_layer = doc.get_page(page1).get_layer(layer1);
let total_pages = f64::ceil(keys.len() as f64 / 2.0); // 2 per page
let mut current_page = 1;
for kv in keys.members() {
add_address_to_page(&current_layer, &font, &font_bold, kv["address"].as_str().unwrap(), 0);
// Add next page when moving to the next position.
if pos >= 2 {
pos = 0;
current_page = current_page + 1;
// Add a page
let (page2, _) = doc.add_page(Mm(210.0), Mm(297.0),"Page 2, Layer 1");
current_layer = doc.get_page(page2).add_layer("Layer 3");
}
add_pk_to_page(&current_layer, &font, &font_bold, kv["private_key"].as_str().unwrap(), 1);
// 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);
// Is the shape stroked? Is the shape closed? Is the shape filled?
let line1 = Line {
@ -39,6 +59,15 @@ pub fn save_to_pdf(addresses: &str, filename: &str) {
// Draw first line
current_layer.add_shape(line1);
// Add footer of page, only once for each pair of addresses
if pos == 0 {
add_footer_to_page(&current_layer, &font, &format!("Page {} of {}", current_page, total_pages));
}
// Add to the position to move to the next set, but remember to add a new page every 2 wallets
// We'll add a new page at the start of the loop, so we add it to the PDF only if required.
pos = pos + 1;
};
doc.save(&mut BufWriter::new(File::create(filename).unwrap())).unwrap();
@ -72,13 +101,22 @@ fn qrcode_scaled(data: &str, scalefactor: usize) -> (Vec<u8>, usize) {
return (scaledimg, finalsize);
}
/**
* Add a footer at the bottom of the page
*/
fn add_footer_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef, footer: &str) {
current_layer.use_text(footer, 10, Mm(5.0), Mm(5.0), &font);
}
/**
* Add the address section to the PDF at `pos`. Note that each page can fit only 2 wallets, so pos has to effectively be either 0 or 1.
*/
fn add_address_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef, font_bold: &IndirectFontRef,address: &str, pos: u32) {
fn add_address_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef, font_bold: &IndirectFontRef, address: &str, pos: u32) {
let (scaledimg, finalsize) = qrcode_scaled(address, 10);
let ypos = 297.0 - 5.0 - (50.0 * ((pos+1) as f64));
// page_height top_margin vertical_padding position
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);
@ -91,10 +129,11 @@ 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, pos: u32) {
fn add_pk_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef, font_bold: &IndirectFontRef, pk: &str, seed: &str, pos: u32) {
let (scaledimg, finalsize) = qrcode_scaled(pk, 10);
let ypos = 297.0 - 5.0 - (50.0 * ((pos+1) as f64));
// 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);
@ -102,6 +141,9 @@ fn add_pk_to_page(current_layer: &PdfLayerReference, font: &IndirectFontRef, fon
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);
}
// And add the seed too.
current_layer.use_text(seed, 8, Mm(10.0), Mm(ypos-25.0), &font);
}
/**

Loading…
Cancel
Save