use std::str::FromStr;
use rgb::ContractId;
use rgbstd::interface::TypedState;
use rgbstd::stl::Precision;
use rgbstd::Chain;
use super::{Beneficiary, RgbInvoice, RgbTransport, TransportParseError};
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct RgbInvoiceBuilder(RgbInvoice);
#[allow(clippy::result_large_err)]
impl RgbInvoiceBuilder {
pub fn new(beneficiary: impl Into<Beneficiary>) -> Self {
Self(RgbInvoice {
transports: vec![RgbTransport::UnspecifiedMeans],
contract: None,
iface: None,
operation: None,
assignment: None,
beneficiary: beneficiary.into(),
owned_state: TypedState::Void,
chain: None,
expiry: None,
unknown_query: none!(),
})
}
pub fn with(contract_id: ContractId, beneficiary: impl Into<Beneficiary>) -> Self {
Self::new(beneficiary).set_contract(contract_id)
}
pub fn rgb20(contract_id: ContractId, beneficiary: impl Into<Beneficiary>) -> Self {
Self::with(contract_id, beneficiary).set_interface("RGB20")
}
pub fn rgb20_anything(beneficiary: impl Into<Beneficiary>) -> Self {
Self::new(beneficiary).set_interface("RGB20")
}
pub fn set_contract(mut self, contract_id: ContractId) -> Self {
self.0.contract = Some(contract_id);
self
}
pub fn set_interface(mut self, name: &'static str) -> Self {
self.0.iface = Some(tn!(name));
self
}
pub fn set_operation(mut self, name: &'static str) -> Self {
self.0.operation = Some(tn!(name));
self
}
pub fn set_assignment(mut self, name: &'static str) -> Self {
self.0.assignment = Some(fname!(name));
self
}
pub fn set_amount_raw(mut self, amount: u64) -> Self {
self.0.owned_state = TypedState::Amount(amount);
self
}
pub fn set_amount(
self,
integer: u64,
decimals: u64,
precision: Precision,
) -> Result<Self, Self> {
let pow = 10u64.pow(precision as u32);
if decimals >= pow {
return Err(self);
}
let Some(mut amount) = integer.checked_mul(pow) else {
return Err(self);
};
amount = amount.checked_add(decimals).expect(
"integer has at least the same number of zeros in the lowest digits as much as \
decimals has digits at most, so overflow is not possible",
);
Ok(self.set_amount_raw(amount))
}
pub unsafe fn set_amount_approx(self, amount: f64, precision: Precision) -> Result<Self, Self> {
if amount <= 0.0 {
return Err(self);
}
let coins = amount.floor();
let cents = amount - coins;
self.set_amount(coins as u64, cents as u64, precision)
}
pub fn set_chain(mut self, chain: impl Into<Chain>) -> Self {
self.0.chain = Some(chain.into());
self
}
pub fn set_expiry_timestamp(mut self, expiry: i64) -> Self {
self.0.expiry = Some(expiry);
self
}
pub fn add_transport(self, transport: &str) -> Result<Self, (Self, TransportParseError)> {
let transport = match RgbTransport::from_str(transport) {
Err(err) => return Err((self, err)),
Ok(transport) => transport,
};
Ok(self.add_transport_raw(transport))
}
pub fn add_transport_raw(mut self, transport: RgbTransport) -> Self {
self.0.transports.push(transport);
self
}
pub fn add_transports<'a>(
self,
transports: impl IntoIterator<Item = &'a str>,
) -> Result<Self, (Self, TransportParseError)> {
let res = transports
.into_iter()
.map(RgbTransport::from_str)
.collect::<Result<Vec<_>, TransportParseError>>();
let transports = match res {
Err(err) => return Err((self, err)),
Ok(transports) => transports,
};
Ok(self.add_transports_raw(transports))
}
pub fn add_transports_raw(
mut self,
transports: impl IntoIterator<Item = RgbTransport>,
) -> Self {
self.0.transports.extend(transports);
self
}
pub fn finish(self) -> RgbInvoice { self.0 }
}