Skip to content

Commit

Permalink
further invoice and interface state improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Oct 17, 2024
1 parent 0bfe36d commit 4427261
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 254 deletions.
10 changes: 2 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion invoice/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ name = "rgbinvoice"

[dependencies]
amplify = { workspace = true }
base58 = "0.2.0"
baid64 = { workspace = true }
strict_encoding = { workspace = true }
bp-core = { workspace = true }
Expand Down
111 changes: 15 additions & 96 deletions invoice/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@

use std::str::FromStr;

use rgb::{AttachId, ContractId, State, StateData};
use strict_encoding::{FieldName, StrictSerialize, TypeName};
use rgb::{ContractId, StateData};
use strict_encoding::{FieldName, SerializeError, StrictSerialize, TypeName};

use crate::invoice::{Beneficiary, InvoiceState, RgbInvoice, RgbTransport, XChainNet};
use crate::TransportParseError;
use crate::{Beneficiary, RgbInvoice, RgbTransport, TransportParseError, XChainNet};

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct RgbInvoiceBuilder(RgbInvoice);
Expand All @@ -40,7 +39,7 @@ impl RgbInvoiceBuilder {
operation: None,
assignment: None,
beneficiary: beneficiary.into(),
owned_state: InvoiceState::Any,
state: None,
expiry: None,
unknown_query: none!(),
})
Expand Down Expand Up @@ -72,106 +71,26 @@ impl RgbInvoiceBuilder {
self
}

/// Set the invoiced state, which includes both state data and an optional attachment
/// information.
///
/// # Panics
///
/// If any state information or attachment requirements are already present in the invoice.
///
/// # See also
///
/// - [`Self::add_state_data`], adding just state data information, not affecting attachment
/// requirements;
/// - [`Self::serialize_state_data`], for adding state data by serializing them from a state
/// object;
/// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state
/// information.
pub fn set_state(mut self, state: State) -> Self {
if !self.0.owned_state.is_any() {
panic!("invoice already has state information");
}
self.0.owned_state = InvoiceState::Specific(state);
self
}

/// Add state data to the invoice.
///
/// NB: This keeps existing attachment requirements.
///
/// # Panics
///
/// If the invoice already have any state information (excluding attachment requirements).
///
/// # See also
///
/// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment
/// requirements;
/// - [`Self::serialize_state_data`], for adding state data by serializing them from a state
/// object;
/// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state
/// information.
pub fn add_state_data(mut self, data: StateData) -> Self {
self.0.owned_state = match self.0.owned_state {
InvoiceState::Any => InvoiceState::Specific(State::from(data)),
InvoiceState::Specific(_) => panic!("invoice already has state information"),
InvoiceState::Attach(attach_id) => InvoiceState::Specific(State::with(data, attach_id)),
};
/// See also [`Self::serialize_state_data`], which adds state data by serializing them from a
/// state object.
pub fn set_state(mut self, data: StateData) -> Self {
self.0.state = Some(data);
self
}

/// Add state data to the invoice by strict-serializing the provided object.
///
/// NB: This keeps existing attachment requirements.
///
/// Use the function carefully, since the common pitfall here is to perform double serialization
/// of an already serialized data type, like `SmallBlob`. This produces an invalid state object
/// which can't be properly parsed later.
///
/// # Panics
///
/// If the invoice already has any state information (excluding attachment requirements).
///
/// # See also
///
/// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment
/// requirements;
/// - [`Self::add_state_data`], adding just state data information, not affecting attachment
/// requirements;
/// - [`Self::add_attachment`], for adding attachment requirement to an existing invoiced state
/// information.
pub fn serialize_state_data(mut self, data: impl StrictSerialize) -> Self {
self.0.owned_state = InvoiceState::Specific(State::from_serialized(data));
self
}

/// Add attachment requirements to an invoice, keeping the rest of the invoice state information
/// unchanged.
///
/// # Panics
///
/// If the invoice already has attachment requirements defined.
///
/// # See also
///
/// - [`Self::set_state`], for redefining the whole of the invoiced state, including attachment
/// requirements;
/// - [`Self::add_state_data`], adding just state data information, not affecting attachment
/// requirements;
/// - [`Self::serialize_state_data`], for adding state data by serializing them from a state
/// object;
pub fn add_attachment(mut self, attach_id: AttachId) -> Result<Self, Self> {
self.0.owned_state = match self.0.owned_state {
InvoiceState::Any => InvoiceState::Attach(attach_id),
InvoiceState::Attach(_)
| InvoiceState::Specific(State {
attach: Some(_), ..
}) => panic!("invoice already has attachment requirements"),
InvoiceState::Specific(mut state) => {
state.attach = Some(attach_id);
InvoiceState::Specific(state)
}
};
/// which can't be properly parsed later. See also [`Self::set_state`], which sets state data
/// directly with no serialization.
pub fn serialize_state_data(
mut self,
data: &impl StrictSerialize,
) -> Result<Self, SerializeError> {
self.0.state = Some(StateData::from_serialized(data)?);
Ok(self)
}

Expand Down
32 changes: 3 additions & 29 deletions invoice/src/invoice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use bp::seals::txout::CloseMethod;
use bp::{InvalidPubkey, OutputPk, PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash};
use indexmap::IndexMap;
use invoice::{AddressNetwork, AddressPayload, Network};
use rgb::{AttachId, ContractId, Layer1, SecretSeal, State};
use rgb::{ContractId, Layer1, SecretSeal, StateData};
use strict_encoding::{FieldName, TypeName};

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
Expand All @@ -37,33 +37,6 @@ pub enum RgbTransport {
UnspecifiedMeans,
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub enum InvoiceState {
Any,
Specific(State),
Attach(AttachId),
}

impl InvoiceState {
pub fn is_any(&self) -> bool { matches!(self, InvoiceState::Any) }

pub fn state(&self) -> Option<&State> {
match self {
InvoiceState::Any => None,
InvoiceState::Specific(s) => Some(s),
InvoiceState::Attach(_) => None,
}
}

pub fn attach_id(&self) -> Option<AttachId> {
match self {
InvoiceState::Any => None,
InvoiceState::Specific(s) => s.attach,
InvoiceState::Attach(id) => Some(*id),
}
}
}

#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[non_exhaustive]
pub enum ChainNet {
Expand Down Expand Up @@ -237,9 +210,10 @@ pub struct RgbInvoice {
pub operation: Option<FieldName>,
pub assignment: Option<FieldName>,
pub beneficiary: XChainNet<Beneficiary>,
pub owned_state: InvoiceState,
pub state: Option<StateData>,
/// UTC unix timestamp
pub expiry: Option<i64>,
// Attachment requirements should go here
pub unknown_query: IndexMap<String, String>,
}

Expand Down
3 changes: 1 addition & 2 deletions invoice/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,5 @@ pub use builder::RgbInvoiceBuilder;
pub use parse::{InvoiceParseError, TransportParseError};

pub use crate::invoice::{
Beneficiary, ChainNet, InvoiceState, Pay2Vout, Pay2VoutError, RgbInvoice, RgbTransport,
XChainNet,
Beneficiary, ChainNet, Pay2Vout, Pay2VoutError, RgbInvoice, RgbTransport, XChainNet,
};
Loading

0 comments on commit 4427261

Please sign in to comment.