Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit c51454d

Browse files
Get federation config from URL if available
1 parent f85e8d4 commit c51454d

File tree

2 files changed

+176
-41
lines changed

2 files changed

+176
-41
lines changed

mutiny-core/src/federation.rs

+174-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::utils::{convert_from_fedimint_invoice, convert_to_fedimint_invoice, now, spawn};
1+
use crate::utils::{
2+
convert_from_fedimint_invoice, convert_to_fedimint_invoice, fetch_with_timeout, now, spawn,
3+
};
24
use crate::{
35
error::{MutinyError, MutinyStorageError},
46
event::PaymentInfo,
@@ -56,6 +58,7 @@ use futures_util::{pin_mut, StreamExt};
5658
use hex_conservative::{DisplayHex, FromHex};
5759
use lightning::{log_debug, log_error, log_info, log_trace, log_warn, util::logger::Logger};
5860
use lightning_invoice::Bolt11Invoice;
61+
use reqwest::Method;
5962
use serde::{de::DeserializeOwned, Deserialize, Serialize};
6063
#[cfg(not(target_arch = "wasm32"))]
6164
use std::time::Instant;
@@ -162,6 +165,39 @@ pub struct FederationIdentity {
162165
pub social_recovery_disabled: Option<bool>,
163166
}
164167

168+
#[derive(Serialize, Deserialize)]
169+
struct FederationMetaConfig {
170+
#[serde(flatten)]
171+
pub federations: std::collections::HashMap<String, FederationMeta>,
172+
}
173+
174+
// This is the FederationUrlConfig that refer to a specific federation
175+
// Normal config information that might exist from their URL.
176+
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq)]
177+
pub struct FederationMeta {
178+
// https://github.com/fedimint/fedimint/tree/master/docs/meta_fields
179+
pub federation_name: Option<String>,
180+
pub federation_expiry_timestamp: Option<String>,
181+
pub welcome_message: Option<String>,
182+
pub gateway_fees: Option<GatewayFees>,
183+
// undocumented parameters that fedi uses: https://meta.dev.fedibtc.com/meta.json
184+
pub default_currency: Option<String>,
185+
pub federation_icon_url: Option<String>,
186+
pub max_balance_msats: Option<u32>,
187+
pub max_invoice_msats: Option<u32>,
188+
pub meta_external_url: Option<String>,
189+
pub onchain_deposits_disabled: Option<bool>,
190+
pub preview_message: Option<String>,
191+
pub sites: Option<Site>,
192+
pub public: Option<bool>,
193+
pub tos_url: Option<String>,
194+
pub popup_end_timestamp: Option<u32>,
195+
pub popup_countdown_message: Option<String>,
196+
pub invite_codes_disabled: Option<bool>,
197+
pub stability_pool_disabled: Option<bool>,
198+
pub social_recovery_disabled: Option<bool>,
199+
}
200+
165201
#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
166202
pub struct Site {
167203
pub id: Option<String>,
@@ -688,6 +724,7 @@ impl<S: MutinyStorage> FederationClient<S> {
688724
self.invite_code.clone(),
689725
gateway_fees,
690726
)
727+
.await
691728
}
692729

693730
// delete_fedimint_storage is not suggested at the moment due to the lack of easy restores
@@ -697,53 +734,150 @@ impl<S: MutinyStorage> FederationClient<S> {
697734
}
698735
}
699736

700-
pub(crate) fn get_federation_identity(
737+
pub(crate) async fn get_federation_identity(
701738
uuid: String,
702739
fedimint_client: ClientHandleArc,
703740
invite_code: InviteCode,
704741
gateway_fees: Option<GatewayFees>,
705742
) -> FederationIdentity {
743+
let federation_id = fedimint_client.federation_id();
744+
let meta_external_url = fedimint_client.get_meta("meta_external_url");
745+
let config = if let Some(ref url) = meta_external_url {
746+
let http_client = reqwest::Client::new();
747+
let request = http_client.request(Method::GET, url);
748+
749+
match fetch_with_timeout(&http_client, request.build().expect("should build req")).await {
750+
Ok(r) => match r.json::<FederationMetaConfig>().await {
751+
Ok(c) => {
752+
if let Some(f) = c.federations.get(&federation_id.to_string()) {
753+
Some(f.clone())
754+
} else {
755+
None
756+
}
757+
}
758+
Err(_) => None,
759+
},
760+
Err(_) => None,
761+
}
762+
} else {
763+
None
764+
};
765+
706766
FederationIdentity {
707767
uuid: uuid.clone(),
708-
federation_id: fedimint_client.federation_id(),
768+
federation_id,
709769
invite_code: invite_code.clone(),
710-
federation_name: fedimint_client.get_meta("federation_name"),
711-
federation_expiry_timestamp: fedimint_client.get_meta("federation_expiry_timestamp"),
712-
welcome_message: fedimint_client.get_meta("welcome_message"),
713-
gateway_fees,
714-
default_currency: fedimint_client.get_meta("default_currency"),
715-
federation_icon_url: fedimint_client.get_meta("federation_icon_url"),
716-
max_balance_msats: fedimint_client
717-
.get_meta("max_balance_msats")
718-
.map(|v| v.parse().unwrap_or(0)),
719-
max_invoice_msats: fedimint_client
720-
.get_meta("max_invoice_msats")
721-
.map(|v| v.parse().unwrap_or(0)),
722-
meta_external_url: fedimint_client.get_meta("meta_external_url"),
723-
onchain_deposits_disabled: fedimint_client
724-
.get_meta("onchain_deposits_disabled")
725-
.map(|v| v.parse().unwrap_or(false)),
726-
preview_message: fedimint_client.get_meta("preview_message"),
727-
sites: fedimint_client
728-
.get_meta("sites")
729-
.map(|v| serde_json::from_str(&v).unwrap_or_default()),
730-
public: fedimint_client
731-
.get_meta("public")
732-
.map(|v| v.parse().unwrap_or(false)),
733-
tos_url: fedimint_client.get_meta("tos_url"),
734-
popup_end_timestamp: fedimint_client
735-
.get_meta("popup_end_timestamp")
736-
.map(|v| v.parse().unwrap_or(0)),
737-
popup_countdown_message: fedimint_client.get_meta("popup_countdown_message"),
738-
invite_codes_disabled: fedimint_client
739-
.get_meta("invite_codes_disabled")
740-
.map(|v| v.parse().unwrap_or(false)),
741-
stability_pool_disabled: fedimint_client
742-
.get_meta("stability_pool_disabled")
743-
.map(|v| v.parse().unwrap_or(false)),
744-
social_recovery_disabled: fedimint_client
745-
.get_meta("social_recovery_disabled")
746-
.map(|v| v.parse().unwrap_or(false)),
770+
federation_name: merge_values(
771+
fedimint_client.get_meta("federation_name").clone(),
772+
config.as_ref().and_then(|c| c.federation_name.clone()),
773+
),
774+
federation_expiry_timestamp: merge_values(
775+
fedimint_client.get_meta("federation_expiry_timestamp"),
776+
config
777+
.as_ref()
778+
.and_then(|c| c.federation_expiry_timestamp.clone()),
779+
),
780+
welcome_message: merge_values(
781+
fedimint_client.get_meta("welcome_message"),
782+
config.as_ref().and_then(|c| c.welcome_message.clone()),
783+
),
784+
gateway_fees, // Already merged using helper function...
785+
default_currency: merge_values(
786+
fedimint_client.get_meta("default_currency"),
787+
config.as_ref().and_then(|c| c.default_currency.clone()),
788+
),
789+
federation_icon_url: merge_values(
790+
fedimint_client.get_meta("federation_icon_url"),
791+
config.as_ref().and_then(|c| c.federation_icon_url.clone()),
792+
),
793+
max_balance_msats: merge_values(
794+
fedimint_client
795+
.get_meta("max_balance_msats")
796+
.map(|v| v.parse().unwrap_or(0)),
797+
config.as_ref().and_then(|c| c.max_balance_msats.clone()),
798+
),
799+
max_invoice_msats: merge_values(
800+
fedimint_client
801+
.get_meta("max_invoice_msats")
802+
.map(|v| v.parse().unwrap_or(0)),
803+
config.as_ref().and_then(|c| c.max_invoice_msats.clone()),
804+
),
805+
meta_external_url, // Already set...
806+
onchain_deposits_disabled: merge_values(
807+
fedimint_client
808+
.get_meta("onchain_deposits_disabled")
809+
.map(|v| v.parse().unwrap_or(false)),
810+
config
811+
.as_ref()
812+
.and_then(|c| c.onchain_deposits_disabled.clone()),
813+
),
814+
preview_message: merge_values(
815+
fedimint_client.get_meta("preview_message"),
816+
config.as_ref().and_then(|c| c.preview_message.clone()),
817+
),
818+
sites: merge_values(
819+
fedimint_client
820+
.get_meta("sites")
821+
.map(|v| serde_json::from_str(&v).unwrap_or_default()),
822+
config.as_ref().and_then(|c| c.sites.clone()),
823+
),
824+
public: merge_values(
825+
fedimint_client
826+
.get_meta("public")
827+
.map(|v| v.parse().unwrap_or(false)),
828+
config.as_ref().and_then(|c| c.public.clone()),
829+
),
830+
tos_url: merge_values(
831+
fedimint_client.get_meta("tos_url"),
832+
config.as_ref().and_then(|c| c.tos_url.clone()),
833+
),
834+
popup_end_timestamp: merge_values(
835+
fedimint_client
836+
.get_meta("popup_end_timestamp")
837+
.map(|v| v.parse().unwrap_or(0)),
838+
config.as_ref().and_then(|c| c.popup_end_timestamp.clone()),
839+
),
840+
popup_countdown_message: merge_values(
841+
fedimint_client
842+
.get_meta("popup_countdown_message")
843+
.map(|v| v.to_string()),
844+
config
845+
.as_ref()
846+
.and_then(|c| c.popup_countdown_message.clone()),
847+
),
848+
invite_codes_disabled: merge_values(
849+
fedimint_client
850+
.get_meta("invite_codes_disabled")
851+
.map(|v| v.parse().unwrap_or(false)),
852+
config
853+
.as_ref()
854+
.and_then(|c| c.invite_codes_disabled.clone()),
855+
),
856+
stability_pool_disabled: merge_values(
857+
fedimint_client
858+
.get_meta("stability_pool_disabled")
859+
.map(|v| v.parse().unwrap_or(false)),
860+
config
861+
.as_ref()
862+
.and_then(|c| c.stability_pool_disabled.clone()),
863+
),
864+
social_recovery_disabled: merge_values(
865+
fedimint_client
866+
.get_meta("social_recovery_disabled")
867+
.map(|v| v.parse().unwrap_or(false)),
868+
config
869+
.as_ref()
870+
.and_then(|c| c.social_recovery_disabled.clone()),
871+
),
872+
}
873+
}
874+
875+
fn merge_values<T>(a: Option<T>, b: Option<T>) -> Option<T> {
876+
match (a, b) {
877+
// If a has value return that; otherwise, use the one from b if available.
878+
(Some(val), _) => Some(val),
879+
(None, Some(val)) => Some(val),
880+
(None, None) => None,
747881
}
748882
}
749883

mutiny-core/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3201,7 +3201,8 @@ pub(crate) async fn create_new_federation<S: MutinyStorage>(
32013201
new_federation.fedimint_client.clone(),
32023202
federation_code.clone(),
32033203
gateway_fees,
3204-
);
3204+
)
3205+
.await;
32053206

32063207
federations
32073208
.write()

0 commit comments

Comments
 (0)