diff --git a/apps/machine/src/App.vue b/apps/machine/src/App.vue
index b353984..b089610 100644
--- a/apps/machine/src/App.vue
+++ b/apps/machine/src/App.vue
@@ -2,13 +2,14 @@
import { onMounted, onUnmounted, ref, computed } from 'vue'
import { useAtmStore } from '@/stores/atm'
import { useTheme } from '@/composables/useTheme'
+import { Sun, Moon } from 'lucide-vue-next'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
const atmStore = useAtmStore()
const { current: currentTheme, themes, colorMode } = useTheme()
const debugExpanded = ref(false)
-const network = import.meta.env.VITE_NETWORK || 'regtest'
+// Network detected dynamically from Lightning invoice prefix
const isElectron = typeof window !== 'undefined' && window.electronAPI !== undefined
function formatSats(sats: number): string {
@@ -76,8 +77,8 @@ function toggleLiveServices() {
-
ATM Unavailable
-
+
ATM Unavailable
+
This machine is temporarily out of service. Please try again later or use another machine.
@@ -89,18 +90,16 @@ function toggleLiveServices() {
-
+
{{ formattedBtcPrice }}
bal: {{ formatSats(atmStore.balanceSats) }} sats
@@ -121,13 +120,25 @@ function toggleLiveServices() {
Mock
- {{ network }}
+ {{ atmStore.network }}
+
+
+
{
const balanceSats = ref(null)
const btcPrice = ref(null) // local fiat per BTC (for display)
const btcPriceUsd = ref(null) // USD per BTC (always shown)
+ const network = ref<'mainnet' | 'testnet' | 'regtest' | null>(
+ (localStorage.getItem('atm-network') as 'mainnet' | 'testnet' | 'regtest') || null
+ )
let stopBalanceWatch: (() => void) | null = null
let pricePollingInterval: ReturnType | null = null
// Store reference to ATM services for direct calls
let atmServicesRef: ATMServices | null = null
+ /** Detect Bitcoin network from a BOLT-11 invoice prefix (called once, persisted) */
+ function detectNetworkFromInvoice(invoice: string) {
+ if (network.value) return // already detected
+ const lower = invoice.toLowerCase()
+ if (lower.startsWith('lnbcrt')) network.value = 'regtest'
+ else if (lower.startsWith('lntb')) network.value = 'testnet'
+ else if (lower.startsWith('lnbc')) network.value = 'mainnet'
+ if (network.value) {
+ localStorage.setItem('atm-network', network.value)
+ console.log('[ATM] Detected network:', network.value)
+ }
+ }
+
// Computed
const currentState = computed(() => {
if (!snapshot.value) return 'uninitialized'
@@ -220,6 +236,11 @@ export const useAtmStore = defineStore('atm', () => {
if ('cashOut' in state) currentNested = state.cashOut as string
}
+ // Detect network from first invoice we see
+ if (newSnapshot.context.invoice) {
+ detectNetworkFromInvoice(newSnapshot.context.invoice)
+ }
+
// Auto-advance past waitingForCashTaken when HAL is connected,
// because HAL's dispenseCash already calls waitForBillsRemoved()
if (
@@ -394,6 +415,7 @@ export const useAtmStore = defineStore('atm', () => {
paymentError.value = null
try {
+ detectNetworkFromInvoice(invoice)
console.log(
'[ATM] Paying invoice:',
invoice.slice(0, 40) + '...',
@@ -999,6 +1021,7 @@ export const useAtmStore = defineStore('atm', () => {
balanceSats,
btcPrice,
btcPriceUsd,
+ network,
halServices,
isPayingInvoice,
isRequestingDebit,