Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow the LiquidAddressData amount_sat precision to be adjusted #1157

Merged
merged 3 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion libs/sdk-common/src/liquid/bip21.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,21 @@ pub struct LiquidAddressData {
pub address: String,
pub network: Network,
pub asset_id: Option<String>,
pub amount: Option<f64>,
pub amount_sat: Option<u64>,
pub label: Option<String>,
pub message: Option<String>,
}

impl LiquidAddressData {
/// Sets the precision for calculating the [LiquidAddressData::amount_sat] from the BIP21 URI amount.
/// By default the precision 8 for Bitcoin-like assets.
pub fn set_amount_precision(&mut self, precision: u32) {
if let Some(amount) = self.amount {
self.amount_sat = Some((amount * (10_u64.pow(precision) as f64)) as u64);
}
}

/// Converts the structure to a BIP21 URI while also
/// ensuring that all the fields are valid
pub fn to_uri(&self) -> Result<String, URISerializationError> {
Expand All @@ -32,6 +41,15 @@ impl LiquidAddressData {

let mut optional_keys = HashMap::new();

if let Some(amount) = self.amount {
let Some(asset_id) = self.asset_id.clone() else {
return Err(URISerializationError::AssetIdMissing);
};

optional_keys.insert("amount", format!("{amount:.8}"));
optional_keys.insert("assetid", asset_id);
}

if let Some(amount_sat) = self.amount_sat {
let Some(asset_id) = self.asset_id.clone() else {
return Err(URISerializationError::AssetIdMissing);
Expand Down Expand Up @@ -110,6 +128,7 @@ impl LiquidAddressData {
.map_err(DeserializeError::InvalidAddress)?
.to_string();

let mut amount = None;
let mut amount_sat = None;
let mut asset_id = None;
let mut label = None;
Expand All @@ -119,6 +138,9 @@ impl LiquidAddressData {
if let Some((key, val)) = pair.split_once('=') {
match key {
"amount" => {
amount = bitcoin::Amount::from_str_in(val, Denomination::Bitcoin)
.map(|amt| Some(amt.to_float_in(Denomination::Bitcoin)))
.map_err(DeserializeError::InvalidAmount)?;
amount_sat = bitcoin::Amount::from_str_in(val, Denomination::Bitcoin)
.map(|amt| Some(amt.to_sat()))
.map_err(DeserializeError::InvalidAmount)?;
Expand Down Expand Up @@ -150,14 +172,15 @@ impl LiquidAddressData {

// "assetid" MUST be provided if "amount" is present
// See https://github.com/ElementsProject/elements/issues/805#issuecomment-576743532
if amount_sat.is_some() && asset_id.is_none() {
if (amount.is_some() || amount_sat.is_some()) && asset_id.is_none() {
return Err(DeserializeError::AssetNotProvided);
}

Ok(Self {
address,
network,
asset_id,
amount,
amount_sat,
label,
message,
Expand All @@ -183,6 +206,7 @@ impl LiquidAddressData {
address: address.to_string(),
network,
asset_id: None,
amount: None,
amount_sat: None,
label: None,
message: None,
Expand Down
1 change: 1 addition & 0 deletions libs/sdk-common/src/liquid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ mod tests {
address: "tlq1qqw5ur50rnvcx33vmljjtnez3hrtl6n7vs44tdj2c9fmnxrrgzgwnhw6jtpn8cljkmlr8tgfw9hemrr5y8u2nu024hhak3tpdk".to_string(),
network: crate::model::Network::Bitcoin,
asset_id: Some(AssetId::LIQUID_BTC.to_string()),
amount: None,
amount_sat: Some(amount_sat),
label: None,
message: None,
Expand Down
Loading