Skip to content

Commit

Permalink
chore: users can leave federations with zero balance
Browse files Browse the repository at this point in the history
  • Loading branch information
tvolk131 committed Oct 3, 2024
1 parent 02875cc commit 08ff2ab
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 8 deletions.
47 changes: 42 additions & 5 deletions src/fedimint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl Wallet {

pub async fn connect_to_joined_federations(&self) -> anyhow::Result<()> {
// Note: We're intentionally locking the clients mutex earlier than
// necessary so that the lock is held while we're reading the data directory.
// necessary so that the lock is held while we're accessing the data directory.
let mut clients = self.clients.lock().await;

// List all files in the data directory.
Expand Down Expand Up @@ -154,9 +154,9 @@ impl Wallet {
Ok(())
}

pub async fn join_federation(&self, invite_code: InviteCode) -> anyhow::Result<()> {
pub async fn join_federation(&self, invite_code: InviteCode) -> anyhow::Result<WalletView> {
// Note: We're intentionally locking the clients mutex earlier than
// necessary so that the lock is held while we're reading the data directory.
// necessary so that the lock is held while we're accessing the data directory.
let mut clients = self.clients.lock().await;

let federation_id = invite_code.federation_id();
Expand All @@ -167,7 +167,7 @@ impl Wallet {

// Short-circuit if we're already connected to this federation.
if federation_data_dir.is_dir() {
return Ok(());
return Ok(Self::get_current_state(clients).await);
}

let db: Database = RocksDb::open(federation_data_dir)?.into();
Expand All @@ -176,7 +176,44 @@ impl Wallet {

clients.insert(federation_id, client);

Ok(())
Ok(Self::get_current_state(clients).await)
}

// TODO: Call `ClientModule::leave()` for every module.
// https://docs.rs/fedimint-client/0.4.2/fedimint_client/module/trait.ClientModule.html#method.leave
// Currently it isn't implemented for the `LightningClientModule`, so for now we're just checking
// that the client has a zero balance.
pub async fn leave_federation(
&self,
federation_id: FederationId,
) -> anyhow::Result<WalletView> {
// Note: We're intentionally locking the clients mutex earlier than
// necessary so that the lock is held while we're accessing the data directory.
let mut clients = self.clients.lock().await;

if let Some(client) = clients.remove(&federation_id) {
if client.get_balance().await.msats != 0 {
// Re-insert the client back into the clients map.
clients.insert(federation_id, client);

return Err(anyhow::anyhow!(
"Cannot leave federation with non-zero balance: {}",
federation_id
));
}

client.shutdown().await;

let federation_data_dir = self
.fedimint_clients_data_dir
.join(federation_id.to_string());

if federation_data_dir.is_dir() {
std::fs::remove_dir_all(federation_data_dir)?;
}
}

Ok(Self::get_current_state(clients).await)
}

async fn get_current_state(
Expand Down
63 changes: 60 additions & 3 deletions src/routes/bitcoin_wallet.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::str::FromStr;
use std::{str::FromStr, sync::Arc};

use fedimint_core::{
config::{ClientConfig, META_FEDERATION_NAME_KEY},
config::{ClientConfig, FederationId, META_FEDERATION_NAME_KEY},
invite_code::InviteCode,
Amount,
};
Expand Down Expand Up @@ -42,6 +42,10 @@ pub enum Message {
JoinFederation(InviteCode),
JoinedFederation(InviteCode),

LeaveFederation(FederationId),
LeftFederation((FederationId, WalletView)),
FailedToLeaveFederation((FederationId, Arc<anyhow::Error>)),

Send(send::Message),
Receive(receive::Message),

Expand Down Expand Up @@ -161,7 +165,9 @@ impl Page {

Task::stream(async_stream::stream! {
match wallet.join_federation(invite_code.clone()).await {
Ok(()) => {
Ok(wallet_view) => {
yield app::Message::UpdateWalletView(wallet_view);

yield app::Message::AddToast(Toast {
title: "Joined federation".to_string(),
body: "You have successfully joined the federation.".to_string(),
Expand Down Expand Up @@ -196,6 +202,38 @@ impl Page {

Task::none()
}
Message::LeaveFederation(federation_id) => {
let wallet = self.connected_state.wallet.clone();

Task::future(async move {
match wallet.leave_federation(federation_id).await {
Ok(wallet_view) => app::Message::Routes(super::Message::BitcoinWalletPage(
Message::LeftFederation((federation_id, wallet_view)),
)),
Err(err) => app::Message::Routes(super::Message::BitcoinWalletPage(
Message::FailedToLeaveFederation((federation_id, Arc::from(err))),
)),
}
})
}
Message::LeftFederation((_federation_id, wallet_view)) => {
Task::done(app::Message::UpdateWalletView(wallet_view))
.chain(Task::done(app::Message::Routes(super::Message::Navigate(
RouteName::BitcoinWallet(SubrouteName::List),
))))
.chain(Task::done(app::Message::AddToast(Toast {
title: "Left federation".to_owned(),
body: "You have successfully left the federation.".to_owned(),
status: ToastStatus::Good,
})))
}
Message::FailedToLeaveFederation((_federation_id, _err)) => {
Task::done(app::Message::AddToast(Toast {
title: "Failed to leave federation".to_owned(),
body: "Could not leave federation.".to_owned(),
status: ToastStatus::Bad,
}))
}
Message::Send(send_message) => {
if let Subroute::Send(send_page) = &mut self.subroute {
send_page.update(send_message)
Expand Down Expand Up @@ -444,6 +482,25 @@ impl FederationDetails {
);
}

let has_zero_balance = self.view.balance.msats == 0;

if !has_zero_balance {
container = container.push(
Text::new("Must have a zero balance in this federation in order to leave.")
.size(20),
);
}

container = container.push(
icon_button("Leave Federation", SvgIcon::Delete, PaletteColor::Danger).on_press_maybe(
has_zero_balance.then(|| {
app::Message::Routes(super::Message::BitcoinWalletPage(
Message::LeaveFederation(self.view.federation_id),
))
}),
),
);

container = container.push(
icon_button("Back", SvgIcon::ArrowBack, PaletteColor::Background).on_press(
app::Message::Routes(super::Message::Navigate(RouteName::BitcoinWallet(
Expand Down

0 comments on commit 08ff2ab

Please sign in to comment.