Skip to content

Commit

Permalink
invoice: add explicit chain information
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Sep 18, 2023
1 parent 7667afb commit f81cdbe
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

52 changes: 50 additions & 2 deletions invoice/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,21 @@ use std::fmt::{self, Debug, Display, Formatter};
use std::num::ParseIntError;
use std::str::FromStr;

use bp::{Address, AddressNetwork};
use bp::{Address, AddressNetwork, Chain, ChainParseError};
use fluent_uri::enc::EStr;
use fluent_uri::Uri;
use indexmap::IndexMap;
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
use rgb::interface::TypedState;
use rgb::{Chain, ContractId, SecretSeal};
use rgb::{ContractId, SecretSeal};
use strict_encoding::{InvalidIdent, TypeName};

use super::{Beneficiary, RgbInvoice, RgbTransport};

const OMITTED: char = '~';
const EXPIRY: &str = "expiry";
const ENDPOINTS: &str = "endpoints";
const CHAIN: &str = "chain";
const TRANSPORT_SEP: char = ',';
const TRANSPORT_HOST_SEP: &str = "://";
const QUERY_ENCODE: &AsciiSet = &CONTROLS
Expand Down Expand Up @@ -106,7 +107,16 @@ pub enum InvoiceParseError {
/// network {0:?} is not supported.
UnsupportedNetwork(AddressNetwork),

/// chain `{chain}` explicitly specified in the invoice doesn't match
/// network `{addr_chain}` used in the provided beneficiary address.
ChainMismatch { chain: Chain, addr_chain: Chain },

#[from]
#[display(inner)]
InvalidChain(ChainParseError),

#[from]
#[display(inner)]
Num(ParseIntError),

#[from]
Expand All @@ -115,14 +125,32 @@ pub enum InvoiceParseError {
}

impl RgbInvoice {
#[inline]
fn non_default_chain(&self) -> Option<Chain> {
if self.beneficiary.has_chain_info() {
return None;
}
if let Some(chain) = self.chain {
if chain != Chain::Bitcoin {
return Some(chain);
}
}
None
}

#[inline]
fn has_params(&self) -> bool {
self.expiry.is_some() ||
self.transports != vec![RgbTransport::UnspecifiedMeans] ||
self.non_default_chain().is_some() ||
!self.unknown_query.is_empty()
}

fn query_params(&self) -> IndexMap<String, String> {
let mut query_params: IndexMap<String, String> = IndexMap::new();
if let Some(chain) = self.non_default_chain() {
query_params.insert(CHAIN.to_string(), chain.to_string());
}
if let Some(expiry) = self.expiry {
query_params.insert(EXPIRY.to_string(), expiry.to_string());
}
Expand Down Expand Up @@ -306,6 +334,26 @@ impl FromStr for RgbInvoice {

let mut query_params = map_query_params(&uri)?;

let chain = if let Some(chain_str) = query_params.remove(CHAIN) {
match (Chain::from_str(&chain_str)?, chain) {
(chain, None) => Some(chain),
(chain, Some(addr_chain)) if chain == addr_chain => Some(chain),
(chain, Some(addr_chain))
if chain.is_testnet() &&
addr_chain.is_testnet() &&
chain != Chain::Regtest &&
addr_chain != Chain::Regtest =>
{
Some(chain)
}
(chain, Some(addr_chain)) => {
return Err(InvoiceParseError::ChainMismatch { chain, addr_chain });
}
}
} else {
None
};

let transports = if let Some(endpoints) = query_params.remove(ENDPOINTS) {
let tokens: Vec<&str> = endpoints.split(TRANSPORT_SEP).collect();
let mut transport_vec: Vec<RgbTransport> = vec![];
Expand Down

0 comments on commit f81cdbe

Please sign in to comment.