hw-wallet 0.1.2

Shared wallet orchestration utilities for CLI and FFI
Documentation
use serde::Deserialize;
use trezor_connect::thp::{BtcInputScriptType, BtcMultisig, BtcSignInput};

use super::multisig::TxInputMultisig;
use super::owner::TxOwner;
use super::sats::parse_sats;
use super::script_type::InputScriptTypeExt;
use crate::bip32::parse_bip32_path;
use crate::error::{WalletError, WalletResult};
use crate::hex::{decode, decode_hash32};

#[derive(Debug, Deserialize)]
pub struct TxInputInput {
    pub path: String,
    pub prev_hash: String,
    pub prev_index: u32,
    pub amount: String,
    #[serde(default = "default_sequence")]
    pub sequence: u32,
    #[serde(default = "default_input_script_type")]
    pub script_type: String,
    pub multisig: Option<TxInputMultisig>,
    pub script_sig: Option<String>,
    pub witness: Option<String>,
    pub orig_hash: Option<String>,
    pub orig_index: Option<u32>,
}

pub(super) fn default_sequence() -> u32 {
    0xffff_ffff
}

fn default_input_script_type() -> String {
    "spendwitness".to_string()
}

impl TxInputInput {
    pub(super) fn into_sign_input(self, owner: TxOwner) -> WalletResult<BtcSignInput> {
        let path = parse_bip32_path(&self.path)?;
        let prev_hash = decode_hash32(owner.input_prev_hash_field(), &self.prev_hash)?;
        let amount = parse_sats(&self.amount)?;
        let script_type = BtcInputScriptType::parse(&self.script_type)?;
        let multisig = self.multisig.map(BtcMultisig::try_from).transpose()?;
        if script_type == BtcInputScriptType::SpendMultisig && multisig.is_none() {
            return Err(WalletError::Signing(
                "bitcoin input with script_type SpendMultisig requires multisig metadata".into(),
            ));
        }
        Ok(BtcSignInput {
            path,
            prev_hash,
            prev_index: self.prev_index,
            amount,
            sequence: self.sequence,
            script_type,
            multisig,
            script_sig: self.script_sig.as_deref().map(decode).transpose()?,
            witness: self.witness.as_deref().map(decode).transpose()?,
            orig_hash: self
                .orig_hash
                .as_deref()
                .map(|value| decode_hash32(owner.input_orig_hash_field(), value))
                .transpose()?,
            orig_index: self.orig_index,
        })
    }
}