diff --git a/neode-ui/src/components/WalletSettingsModal.vue b/neode-ui/src/components/WalletSettingsModal.vue
index d3e54397..a9559b46 100644
--- a/neode-ui/src/components/WalletSettingsModal.vue
+++ b/neode-ui/src/components/WalletSettingsModal.vue
@@ -120,6 +120,7 @@
{{ fedError }}
+ Federation joined.
@@ -178,6 +179,7 @@ const federations = ref([])
const inviteCode = ref('')
const joiningFed = ref(false)
const fedError = ref('')
+const fedJoinedOk = ref(false)
watch(
() => props.show,
@@ -259,18 +261,36 @@ async function loadFederations() {
async function joinFederation() {
if (!fedimintBackendReady || !inviteCode.value.trim()) return
+ const before = federations.value.length
joiningFed.value = true
fedError.value = ''
+ fedJoinedOk.value = false
try {
await rpcClient.call<{ federation_id: string }>({
method: 'wallet.fedimint-join',
params: { invite_code: inviteCode.value.trim() },
+ // Joining a federation is heavy (downloads the federation config + joins
+ // the consensus); it routinely takes longer than the default 15s. Give it
+ // headroom past the backend's own 60s clientd timeout.
+ timeout: 90000,
})
inviteCode.value = ''
await loadFederations()
+ fedJoinedOk.value = true
emit('changed')
} catch (err: unknown) {
- fedError.value = err instanceof Error ? err.message : 'Failed to join federation'
+ // A slow join often still completes server-side after the client gives up,
+ // so don't cry failure blindly — re-check the list. If a new federation
+ // appeared, the join actually worked; surface success instead of a scary
+ // (and wrong) timeout error.
+ await loadFederations()
+ if (federations.value.length > before) {
+ inviteCode.value = ''
+ fedJoinedOk.value = true
+ emit('changed')
+ } else {
+ fedError.value = err instanceof Error ? err.message : 'Failed to join federation'
+ }
} finally {
joiningFed.value = false
}