Skip to content

Commit f81cdbe

Browse files
committed
invoice: add explicit chain information
1 parent 7667afb commit f81cdbe

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

invoice/src/parse.rs

+50-2
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,21 @@ use std::fmt::{self, Debug, Display, Formatter};
2323
use std::num::ParseIntError;
2424
use std::str::FromStr;
2525

26-
use bp::{Address, AddressNetwork};
26+
use bp::{Address, AddressNetwork, Chain, ChainParseError};
2727
use fluent_uri::enc::EStr;
2828
use fluent_uri::Uri;
2929
use indexmap::IndexMap;
3030
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
3131
use rgb::interface::TypedState;
32-
use rgb::{Chain, ContractId, SecretSeal};
32+
use rgb::{ContractId, SecretSeal};
3333
use strict_encoding::{InvalidIdent, TypeName};
3434

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

3737
const OMITTED: char = '~';
3838
const EXPIRY: &str = "expiry";
3939
const ENDPOINTS: &str = "endpoints";
40+
const CHAIN: &str = "chain";
4041
const TRANSPORT_SEP: char = ',';
4142
const TRANSPORT_HOST_SEP: &str = "://";
4243
const QUERY_ENCODE: &AsciiSet = &CONTROLS
@@ -106,7 +107,16 @@ pub enum InvoiceParseError {
106107
/// network {0:?} is not supported.
107108
UnsupportedNetwork(AddressNetwork),
108109

110+
/// chain `{chain}` explicitly specified in the invoice doesn't match
111+
/// network `{addr_chain}` used in the provided beneficiary address.
112+
ChainMismatch { chain: Chain, addr_chain: Chain },
113+
109114
#[from]
115+
#[display(inner)]
116+
InvalidChain(ChainParseError),
117+
118+
#[from]
119+
#[display(inner)]
110120
Num(ParseIntError),
111121

112122
#[from]
@@ -115,14 +125,32 @@ pub enum InvoiceParseError {
115125
}
116126

117127
impl RgbInvoice {
128+
#[inline]
129+
fn non_default_chain(&self) -> Option<Chain> {
130+
if self.beneficiary.has_chain_info() {
131+
return None;
132+
}
133+
if let Some(chain) = self.chain {
134+
if chain != Chain::Bitcoin {
135+
return Some(chain);
136+
}
137+
}
138+
None
139+
}
140+
141+
#[inline]
118142
fn has_params(&self) -> bool {
119143
self.expiry.is_some() ||
120144
self.transports != vec![RgbTransport::UnspecifiedMeans] ||
145+
self.non_default_chain().is_some() ||
121146
!self.unknown_query.is_empty()
122147
}
123148

124149
fn query_params(&self) -> IndexMap<String, String> {
125150
let mut query_params: IndexMap<String, String> = IndexMap::new();
151+
if let Some(chain) = self.non_default_chain() {
152+
query_params.insert(CHAIN.to_string(), chain.to_string());
153+
}
126154
if let Some(expiry) = self.expiry {
127155
query_params.insert(EXPIRY.to_string(), expiry.to_string());
128156
}
@@ -306,6 +334,26 @@ impl FromStr for RgbInvoice {
306334

307335
let mut query_params = map_query_params(&uri)?;
308336

337+
let chain = if let Some(chain_str) = query_params.remove(CHAIN) {
338+
match (Chain::from_str(&chain_str)?, chain) {
339+
(chain, None) => Some(chain),
340+
(chain, Some(addr_chain)) if chain == addr_chain => Some(chain),
341+
(chain, Some(addr_chain))
342+
if chain.is_testnet() &&
343+
addr_chain.is_testnet() &&
344+
chain != Chain::Regtest &&
345+
addr_chain != Chain::Regtest =>
346+
{
347+
Some(chain)
348+
}
349+
(chain, Some(addr_chain)) => {
350+
return Err(InvoiceParseError::ChainMismatch { chain, addr_chain });
351+
}
352+
}
353+
} else {
354+
None
355+
};
356+
309357
let transports = if let Some(endpoints) = query_params.remove(ENDPOINTS) {
310358
let tokens: Vec<&str> = endpoints.split(TRANSPORT_SEP).collect();
311359
let mut transport_vec: Vec<RgbTransport> = vec![];

0 commit comments

Comments
 (0)