mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-14 03:30:02 +00:00
120 lines
4.6 KiB
Rust
120 lines
4.6 KiB
Rust
use std::io::{self, Write};
|
|
|
|
use bitcoin::{
|
|
bip32, blockdata::script::Builder, consensus::encode::Decodable, network::Network, psbt,
|
|
transaction::Version, Address, Amount, Sequence, Transaction, TxIn, TxOut,
|
|
};
|
|
|
|
use trezor_client::{Error, SignTxProgress, TrezorMessage, TrezorResponse};
|
|
|
|
fn handle_interaction<T, R: TrezorMessage>(resp: TrezorResponse<T, R>) -> T {
|
|
match resp {
|
|
TrezorResponse::Ok(res) => res,
|
|
// assering ok() returns the failure error
|
|
TrezorResponse::Failure(_) => resp.ok().unwrap(),
|
|
TrezorResponse::ButtonRequest(req) => handle_interaction(req.ack().unwrap()),
|
|
TrezorResponse::PinMatrixRequest(req) => {
|
|
println!("Enter PIN");
|
|
let mut pin = String::new();
|
|
if io::stdin().read_line(&mut pin).unwrap() != 5 {
|
|
println!("must enter pin, received: {}", pin);
|
|
}
|
|
// trim newline
|
|
handle_interaction(req.ack_pin(pin[..4].to_owned()).unwrap())
|
|
}
|
|
TrezorResponse::PassphraseRequest(req) => {
|
|
println!("Enter passphrase");
|
|
let mut pass = String::new();
|
|
io::stdin().read_line(&mut pass).unwrap();
|
|
// trim newline
|
|
handle_interaction(req.ack_passphrase(pass[..pass.len() - 1].to_owned()).unwrap())
|
|
}
|
|
}
|
|
}
|
|
|
|
fn tx_progress(
|
|
psbt: &mut psbt::Psbt,
|
|
progress: SignTxProgress,
|
|
raw_tx: &mut Vec<u8>,
|
|
) -> Result<(), Error> {
|
|
if let Some(part) = progress.get_serialized_tx_part() {
|
|
raw_tx.write_all(part).unwrap();
|
|
}
|
|
|
|
if !progress.finished() {
|
|
let progress = handle_interaction(progress.ack_psbt(psbt, Network::Testnet).unwrap());
|
|
tx_progress(psbt, progress, raw_tx)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
tracing_subscriber::fmt().with_max_level(tracing::Level::TRACE).init();
|
|
|
|
// init with debugging
|
|
let mut trezor = trezor_client::unique(false).unwrap();
|
|
trezor.init_device(None).unwrap();
|
|
|
|
let pubkey = handle_interaction(
|
|
trezor
|
|
.get_public_key(
|
|
&vec![
|
|
bip32::ChildNumber::from_hardened_idx(0).unwrap(),
|
|
bip32::ChildNumber::from_hardened_idx(0).unwrap(),
|
|
bip32::ChildNumber::from_hardened_idx(1).unwrap(),
|
|
]
|
|
.into(),
|
|
trezor_client::protos::InputScriptType::SPENDADDRESS,
|
|
Network::Testnet,
|
|
true,
|
|
)
|
|
.unwrap(),
|
|
);
|
|
let addr = Address::p2pkh(&pubkey.to_pub(), Network::Testnet);
|
|
println!("address: {}", addr);
|
|
|
|
let mut psbt = psbt::Psbt {
|
|
unsigned_tx: Transaction {
|
|
version: Version::ONE,
|
|
lock_time: bitcoin::absolute::LockTime::from_consensus(0),
|
|
input: vec![TxIn {
|
|
previous_output: "c5bdb27907b78ce03f94e4bf2e94f7a39697b9074b79470019e3dbc76a10ecb6:0".parse().unwrap(),
|
|
sequence: Sequence(0xffffffff),
|
|
script_sig: Builder::new().into_script(),
|
|
witness: Default::default(),
|
|
}],
|
|
output: vec![TxOut {
|
|
value: Amount::from_sat(14245301),
|
|
script_pubkey: addr.script_pubkey(),
|
|
}],
|
|
},
|
|
inputs: vec![psbt::Input {
|
|
non_witness_utxo: Some(Transaction::consensus_decode(&mut &hex::decode("020000000001011eb5a3e65946f88b00d67b321e5fd980b32a2316fb1fc9b712baa6a1033a04e30100000017160014f0f81ee77d552b4c81497451d1abf5c22ce8e352feffffff02b55dd900000000001976a9142c3cf5686f47c1de9cc90b4255cc2a1ef8c01b3188acfb0391ae6800000017a914a3a79e37ad366d9bf9471b28a9a8f64b50de0c968702483045022100c0aa7b262967fc2803c8a9f38f26682edba7cafb7d4870ebdc116040ad5338b502205dfebd08e993af2e6aa3118a438ad70ed9f6e09bc6abfd21f8f2957af936bc070121031f4e69fcf110bb31f019321834c0948b5487f2782489f370f66dc20f7ac767ca8bf81500").unwrap()[..]).unwrap()),
|
|
..Default::default()
|
|
}],
|
|
outputs: vec![
|
|
psbt::Output {
|
|
..Default::default()
|
|
},
|
|
],
|
|
proprietary: Default::default(),
|
|
unknown: Default::default(),
|
|
version: 0,
|
|
xpub: Default::default(),
|
|
};
|
|
|
|
println!("psbt before: {:?}", psbt);
|
|
println!("unsigned txid: {}", psbt.unsigned_tx.txid());
|
|
println!(
|
|
"unsigned tx: {}",
|
|
hex::encode(bitcoin::consensus::encode::serialize(&psbt.unsigned_tx))
|
|
);
|
|
|
|
let mut raw_tx = Vec::new();
|
|
let progress = handle_interaction(trezor.sign_tx(&psbt, Network::Testnet).unwrap());
|
|
tx_progress(&mut psbt, progress, &mut raw_tx).unwrap();
|
|
|
|
println!("signed tx: {}", hex::encode(raw_tx));
|
|
}
|