From 03857ca835691d3b57adbd9074fb2c85e1536d77 Mon Sep 17 00:00:00 2001 From: xscd Date: Sun, 30 May 2021 14:53:43 +0300 Subject: [PATCH] Print the Bitcoin address to the terminal as a QR code --- CHANGELOG.md | 5 ++++ Cargo.lock | 56 +++++++++++++++++++++++++++++++++++++++++++- swap/Cargo.toml | 1 + swap/src/bin/swap.rs | 25 ++++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb62f50b..03c055b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Printing the deposit address to the terminal as a QR code. + To not break automated scripts or integrations with other software, this behaviour is disabled if `--json` is passed to the application. + ## [0.7.0] - 2021-05-28 ### Fixed diff --git a/Cargo.lock b/Cargo.lock index a92f090a..eaa39b13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -486,6 +486,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytemuck" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58" + [[package]] name = "byteorder" version = "1.4.3" @@ -578,6 +584,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "checked_int_cast" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919" + [[package]] name = "chrono" version = "0.4.19" @@ -624,6 +636,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "config" version = "0.11.0" @@ -1560,6 +1578,20 @@ dependencies = [ "libc", ] +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-iter", + "num-rational 0.3.2", + "num-traits", +] + [[package]] name = "indexmap" version = "1.6.2" @@ -2372,7 +2404,7 @@ dependencies = [ "num-complex", "num-integer", "num-iter", - "num-rational", + "num-rational 0.1.42", "num-traits", ] @@ -2431,6 +2463,17 @@ dependencies = [ "rustc-serialize", ] +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -2833,6 +2876,16 @@ dependencies = [ "prost", ] +[[package]] +name = "qrcode" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f" +dependencies = [ + "checked_int_cast", + "image", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -3913,6 +3966,7 @@ dependencies = [ "port_check", "prettytable-rs", "proptest", + "qrcode", "rand 0.8.3", "rand_chacha 0.3.0", "reqwest", diff --git a/swap/Cargo.toml b/swap/Cargo.toml index ba8ed7b3..51cb8e84 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -37,6 +37,7 @@ monero-rpc = { path = "../monero-rpc" } pem = "0.8" prettytable-rs = "0.8" proptest = "1" +qrcode = "0.12" rand = "0.8" rand_chacha = "0.3" reqwest = { version = "0.11", features = [ "rustls-tls", "stream", "socks" ], default-features = false } diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index 314b5697..1db5b150 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -14,6 +14,8 @@ use anyhow::{bail, Context, Result}; use prettytable::{row, Table}; +use qrcode::render::unicode; +use qrcode::QrCode; use std::cmp::min; use std::env; use std::future::Future; @@ -101,6 +103,7 @@ async fn main() -> Result<()> { let max_givable = || bitcoin_wallet.max_giveable(TxLock::script_size()); let (amount, fees) = determine_btc_to_swap( + json, event_loop_handle.request_quote(), bitcoin_wallet.new_address(), || bitcoin_wallet.balance(), @@ -325,7 +328,18 @@ async fn init_monero_wallet( Ok((monero_wallet, monero_wallet_rpc_process)) } +fn qr_code(value: &impl ToString) -> Result { + let code = QrCode::new(value.to_string())?; + let qr_code = code + .render::() + .dark_color(unicode::Dense1x2::Light) + .light_color(unicode::Dense1x2::Dark) + .build(); + Ok(qr_code) +} + async fn determine_btc_to_swap( + json: bool, bid_quote: impl Future>, get_new_address: impl Future>, balance: FB, @@ -358,6 +372,10 @@ where let minimum_amount = bid_quote.min_quantity; let maximum_amount = bid_quote.max_quantity; + if !json { + eprintln!("{}", qr_code(&deposit_address)?); + } + info!( %deposit_address, %current_maximum_giveable, @@ -449,6 +467,7 @@ mod tests { ]))); let (amount, fees) = determine_btc_to_swap( + true, async { Ok(quote_with_max(0.01)) }, get_dummy_address(), || async { Ok(Amount::from_btc(0.001)?) }, @@ -475,6 +494,7 @@ mod tests { ]))); let (amount, fees) = determine_btc_to_swap( + true, async { Ok(quote_with_max(0.01)) }, get_dummy_address(), || async { Ok(Amount::from_btc(0.1001)?) }, @@ -502,6 +522,7 @@ mod tests { ]))); let (amount, fees) = determine_btc_to_swap( + true, async { Ok(quote_with_max(0.01)) }, async { panic!("should not request new address when initial balance is > 0") }, || async { Ok(Amount::from_btc(0.005)?) }, @@ -529,6 +550,7 @@ mod tests { ]))); let (amount, fees) = determine_btc_to_swap( + true, async { Ok(quote_with_max(0.01)) }, async { panic!("should not request new address when initial balance is > 0") }, || async { Ok(Amount::from_btc(0.1001)?) }, @@ -556,6 +578,7 @@ mod tests { ]))); let (amount, fees) = determine_btc_to_swap( + true, async { Ok(quote_with_min(0.01)) }, get_dummy_address(), || async { Ok(Amount::from_btc(0.0101)?) }, @@ -583,6 +606,7 @@ mod tests { ]))); let (amount, fees) = determine_btc_to_swap( + true, async { Ok(quote_with_min(0.01)) }, get_dummy_address(), || async { Ok(Amount::from_btc(0.0101)?) }, @@ -615,6 +639,7 @@ mod tests { let error = tokio::time::timeout( Duration::from_secs(1), determine_btc_to_swap( + true, async { Ok(quote_with_min(0.1)) }, get_dummy_address(), || async { Ok(Amount::from_btc(0.0101)?) },