use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
use bitcoin::{Script, TxOut};
use crate::psbt::PsbtExt;
mod error;
pub use error::RequestError;
use error::InternalRequestError;
pub trait Headers {
fn get_header(&self, key: &str) -> Option<&str>;
}
pub struct UncheckedProposal {
psbt: Psbt,
}
impl UncheckedProposal {
pub fn from_request(body: impl std::io::Read, query: &str, headers: impl Headers) -> Result<Self, RequestError> {
use crate::bitcoin::consensus::Decodable;
let content_type = headers.get_header("content-type").ok_or(InternalRequestError::MissingHeader("Content-Type"))?;
if content_type != "text/plain" {
return Err(InternalRequestError::InvalidContentType(content_type.to_owned()).into());
}
let content_length = headers
.get_header("content-length")
.ok_or(InternalRequestError::MissingHeader("Content-Length"))?
.parse::<u64>()
.map_err(InternalRequestError::InvalidContentLength)?;
if content_length > 4_000_000 * 4 / 3 {
return Err(InternalRequestError::ContentLengthTooLarge(content_length).into());
}
let mut limited = body.take(content_length);
let reader = base64::read::DecoderReader::new(&mut limited, base64::STANDARD);
let psbt = Psbt::consensus_decode(reader).map_err(InternalRequestError::Decode)?;
Ok(UncheckedProposal {
psbt,
})
}
pub fn get_transaction_to_check_broadcast(&self) -> bitcoin::Transaction {
self.psbt.clone().extract_tx()
}
pub fn assume_broadcastability_was_verified(self) -> UnlockedProposal {
UnlockedProposal {
psbt: self.psbt,
}
}
pub fn this_is_purely_interactive_wallet(self) -> UnlockedProposal {
UnlockedProposal {
psbt: self.psbt,
}
}
}
pub struct UnlockedProposal {
psbt: Psbt,
}
impl UnlockedProposal {
pub fn utxos_to_be_locked(&self) -> impl '_ + Iterator<Item=&bitcoin::OutPoint> {
self.psbt.global.unsigned_tx.input.iter().map(|input| &input.previous_output)
}
pub fn assume_locked(self) -> Proposal {
Proposal {
psbt: self.psbt,
}
}
}
#[must_use = "The transaction must be broadcasted to prevent abuse"]
pub struct MustBroadcast(pub bitcoin::Transaction);
pub struct Proposal {
psbt: Psbt,
}
pub struct ReceiverOptions {
dust_limit: bitcoin::Amount,
}
pub enum BumpFeePolicy {
FailOnInsufficient,
SubtractOurFeeOutput,
}
pub struct NewOutputOptions {
set_as_fee_output: bool,
subtract_fees_from_this: bool,
}