Files

2254 lines
65 KiB
TypeScript

import { action, observable, runInAction } from 'mobx';
import { BiometryType } from 'react-native-biometrics';
import ReactNativeBlobUtil from 'react-native-blob-util';
import EncryptedStorage from 'react-native-encrypted-storage';
import isEqual from 'lodash/isEqual';
import BackendUtils from '../utils/BackendUtils';
import { getSupportedBiometryType } from '../utils/BiometricUtils';
import { localeString } from '../utils/LocaleUtils';
import MigrationsUtils from '../utils/MigrationUtils';
import { doTorRequest, RequestMethod } from '../utils/TorUtils';
import {
DEFAULT_SCORER_URL,
DEFAULT_VSS_SERVER,
getDefaultEsploraServer,
getDefaultRgsServer,
SupportedNetwork
} from '../utils/LdkNodeUtils';
import Storage from '../storage';
// lndhub
import LoginRequest from '../models/LoginRequest';
const LEGACY_STORAGE_KEY = 'zeus-settings';
export const STORAGE_KEY = 'zeus-settings-v2';
export const LEGACY_CURRENCY_CODES_KEY = 'currency-codes';
export const CURRENCY_CODES_KEY = 'zeus-currency-codes';
export const FAVORITE_CURRENCIES_KEY = 'zeus-favorite-currencies';
export interface Node {
host?: string;
port?: string;
url?: string;
macaroonHex?: string;
rune?: string;
accessKey?: string;
implementation?: string;
certVerification: boolean;
enableTor?: boolean;
nickname?: string;
dismissCustodialWarning: boolean;
photo?: string;
// LNC
pairingPhrase?: string;
mailboxServer?: string;
customMailboxServer?: string;
// NWC
nostrWalletConnectUrl?: string;
// Embedded LND
seedPhrase?: string[];
walletPassword?: string;
adminMacaroon?: string;
embeddedLndNetwork?: string;
lndDir?: string;
isSqlite?: boolean;
// Embedded LDK Node
ldkNetwork?: string;
ldkNodeDir?: string;
ldkMnemonic?: string;
ldkPassphrase?: string;
ldkEsploraServer?: string;
ldkRgsServer?: string;
ldkScorerUrl?: string;
ldkVssServer?: string;
}
interface PrivacySettings {
defaultBlockExplorer?: string;
customBlockExplorer?: string;
clipboard?: boolean;
lurkerMode?: boolean;
enableMempoolRates?: boolean;
// Stealth Mode (Android only)
stealthMode?: boolean;
stealthApp?: 'zeus' | 'calculator' | 'vpn' | 'qrscanner' | 'notepad';
// Stealth unlock configuration
stealthPinLength?: number; // Number of taps required (default 5)
stealthVpnCountry?: string; // VPN unlock country
stealthVpnServer?: string; // VPN unlock server
}
interface DisplaySettings {
theme?: string;
defaultView?: string;
displayNickname?: boolean;
bigKeypadButtons?: boolean;
showAllDecimalPlaces?: boolean;
removeDecimalSpaces?: boolean;
showMillisatoshiAmounts?: boolean;
}
export enum PosEnabled {
Disabled = 'disabled',
Square = 'square',
Standalone = 'standalone'
}
export enum DefaultInvoiceType {
Unified = 'unified',
Lightning = 'lightning'
}
interface PosSettings {
posEnabled?: PosEnabled;
squareEnabled?: boolean;
squareAccessToken?: string;
squareLocationId?: string;
merchantName?: string;
confirmationPreference?: string;
disableTips?: boolean;
squareDevMode?: boolean;
showKeypad?: boolean;
taxPercentage?: string;
enablePrinter?: boolean;
defaultView?: string;
}
interface PaymentsSettings {
defaultFeeMethod?: string; // deprecated
defaultFeePercentage?: string;
defaultFeeFixed?: string;
timeoutSeconds?: string;
preferredMempoolRate?: string;
slideToPayThreshold: number;
enableDonations?: boolean;
defaultDonationPercentage?: number;
}
interface InvoicesSettings {
addressType?: string;
memo?: string;
receiverName?: string;
expiry?: string;
timePeriod?: string;
expirySeconds?: string;
routeHints?: boolean;
ampInvoice?: boolean;
blindedPaths: boolean;
showCustomPreimageField?: boolean;
displayAmountOnInvoice?: boolean; // deprecated
defaultInvoiceType?: DefaultInvoiceType;
}
interface ChannelsSettings {
min_confs: number;
privateChannel: boolean;
scidAlias: boolean;
simpleTaprootChannel: boolean;
}
interface LightningAddressSettings {
enabled: boolean;
automaticallyAccept: boolean;
automaticallyAcceptAttestationLevel: number;
automaticallyRequestOlympusChannels: boolean; // deprecated
routeHints: boolean;
allowComments: boolean;
zapReceiptsEnabled: boolean;
nostrPrivateKey: string;
nostrRelays: Array<string>;
notifications: number;
mintUrl: string; // Cashu
posEnabled?: boolean; // ZEUS Pay+
}
interface Bolt12AddressSettings {
localPart: string;
}
interface EcashSettings {
enableCashu: boolean;
enableMultiMint: boolean;
automaticallySweep: boolean;
sweepThresholdSats?: number;
initialMintUrls?: string[];
}
interface SwapsSettings {
hostMainnet: string;
hostTestnet: string;
customHost: string;
proEnabled: boolean;
}
export interface Settings {
nodes?: Array<Node>;
selectedNode?: number;
justDeletedWallet?: boolean;
passphrase?: string;
duressPassphrase?: string;
pin?: string;
duressPin?: string;
scramblePin?: boolean;
loginBackground?: boolean;
authenticationAttempts?: number;
fiatEnabled?: boolean;
fiat?: string;
fiatRatesSource: 'Zeus' | 'Yadio';
locale?: string;
privacy: PrivacySettings;
display: DisplaySettings;
pos: PosSettings;
payments: PaymentsSettings;
invoices: InvoicesSettings;
channels: ChannelsSettings;
isBiometryEnabled: boolean;
supportedBiometryType?: BiometryType;
lndHubLnAuthMode?: string;
// Embedded node
automaticDisasterRecoveryBackup: boolean;
expressGraphSync: boolean;
resetExpressGraphSyncOnStartup: boolean;
bimodalPathfinding: boolean;
graphSyncPromptNeverAsk: boolean;
graphSyncPromptIgnoreOnce: boolean;
dontAllowOtherPeers: boolean;
neutrinoPeersMainnet: Array<string>;
neutrinoPeersTestnet: Array<string>;
zeroConfPeers: Array<string>;
rescan: boolean;
compactDb: boolean;
recovery: boolean;
initialLoad: boolean;
embeddedTor: boolean;
feeEstimator: string;
customFeeEstimator: string;
speedloader: string;
customSpeedloader: string;
// LSP
enableLSP: boolean;
lspMainnet: string;
lspTestnet: string;
lspMutinynet: string;
lspAccessKey: string;
requestSimpleTaproot: boolean;
//LSPS1
lsps1RestMainnet: string;
lsps1RestTestnet: string;
lsps1RestMutinynet: string;
lsps1PubkeyMainnet: string;
lsps1PubkeyTestnet: string;
lsps1PubkeyMutinynet: string;
lsps1HostMainnet: string;
lsps1HostTestnet: string;
lsps1HostMutinynet: string;
lsps1Token: string;
lsps1ShowPurchaseButton?: boolean; // deprecated
// Swaps
swaps: SwapsSettings;
// Lightning Address
lightningAddress: LightningAddressSettings;
bolt12Address: Bolt12AddressSettings;
selectNodeOnStartup: boolean;
ecash: EcashSettings;
networking?: NetworkingSettings;
}
interface NetworkingSettings {
disableOfflineCheck?: boolean;
}
export const FIAT_RATES_SOURCE_KEYS = [
{ key: 'ZEUS', value: 'Zeus' },
{ key: 'Yadio', value: 'Yadio' }
];
export const BLOCK_EXPLORER_KEYS = [
{ key: 'mempool.space', value: 'mempool.space' },
{ key: 'blockstream.info', value: 'blockstream.info' },
{
key: 'Custom',
translateKey: 'views.Settings.Privacy.BlockExplorer.custom',
value: 'Custom'
}
];
export const MEMPOOL_RATES_KEYS = [
{
key: 'Fastest fee',
value: 'fastestFee',
translateKey: 'views.EditFee.fastestFee'
},
{
key: 'Half hour fee',
value: 'halfHourFee',
translateKey: 'views.EditFee.halfHourFee'
},
{
key: 'Hour fee',
value: 'hourFee',
translateKey: 'views.EditFee.hourFee'
},
{
key: 'Minimum fee',
value: 'minimumFee',
translateKey: 'views.EditFee.minimumFee'
}
];
export const DEFAULT_FEE_ESTIMATOR =
'https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json';
export const FEE_ESTIMATOR_KEYS = [
{
key: 'lightning.computer',
value: 'https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json'
},
{
key: 'strike.me',
value: 'https://bitcoinchainfees.strike.me/v1/fee-estimates'
},
{
key: 'Custom',
translateKey: 'views.Settings.Privacy.BlockExplorer.custom',
value: 'Custom'
}
];
export const SWAP_HOST_KEYS_MAINNET = [
{
key: 'ZEUS',
value: 'https://swaps.zeuslsp.com/api/v2',
pro: false,
supportsRescue: true
},
{
key: 'Boltz',
value: 'https://api.boltz.exchange/v2',
pro: true,
supportsRescue: true
},
{
key: 'SwapMarket',
value: 'https://api.middle-way.space/v2',
pro: false,
supportsRescue: true
},
{
key: 'Eldamar Swaps',
value: 'https://boltz-api.eldamar.icu/v2',
pro: false,
supportsRescue: true
},
{
key: 'Custom',
translateKey: 'views.Settings.Privacy.BlockExplorer.custom',
value: 'Custom',
pro: true,
supportsRescue: true
}
];
export const SWAP_HOST_KEYS_TESTNET = [
{
key: 'ZEUS',
value: 'https://testnet-swaps.zeuslsp.com/api/v2',
pro: false,
supportsRescue: true
},
{
key: 'Boltz',
value: 'https://api.testnet.boltz.exchange/v2',
pro: false,
supportsRescue: true
},
{
key: 'Custom',
translateKey: 'views.Settings.Privacy.BlockExplorer.custom',
value: 'Custom',
pro: true,
supportsRescue: true
}
];
export const DEFAULT_SPEEDLOADER = 'https://egs.lnze.us/';
export const SPEEDLOADER_KEYS = [
{
key: 'ZEUS',
value: 'https://egs.lnze.us/'
},
{
key: 'Blixt',
value: 'https://primer.blixtwallet.com/'
},
{
key: 'Custom',
translateKey: 'views.Settings.Privacy.BlockExplorer.custom',
value: 'Custom'
}
];
export const INTERFACE_KEYS: {
key: string;
value: string;
isHeader?: boolean;
}[] = [
{ key: 'On-device', value: '', isHeader: true },
{ key: 'LDK Node', value: 'ldk-node' },
{ key: 'Embedded LND', value: 'embedded-lnd' },
{ key: 'Remote', value: '', isHeader: true },
{ key: 'LND (REST)', value: 'lnd' },
{ key: 'LND (Lightning Node Connect)', value: 'lightning-node-connect' },
{ key: 'Core Lightning (CLNRest)', value: 'cln-rest' },
{ key: 'Nostr Wallet Connect', value: 'nostr-wallet-connect' },
{ key: 'LNDHub', value: 'lndhub' }
];
export type Implementations =
| 'embedded-lnd'
| 'ldk-node'
| 'lnd'
| 'lightning-node-connect'
| 'cln-rest'
| 'lndhub'
| 'nostr-wallet-connect';
export const EMBEDDED_NODE_NETWORK_KEYS = [
{ key: 'Mainnet', translateKey: 'network.mainnet', value: 'mainnet' },
{ key: 'Testnet', translateKey: 'network.testnet', value: 'testnet' },
{
key: 'Mutinynet',
translateKey: 'network.mutinynet',
value: 'mutinynet'
}
];
export const LDK_VSS_SERVER_KEYS = [
{ key: 'ZEUS', value: DEFAULT_VSS_SERVER },
{ key: 'Custom', translateKey: 'general.custom', value: 'custom' }
];
export const LNC_MAILBOX_KEYS = [
{
key: 'mailbox.terminal.lightning.today:443',
value: 'mailbox.terminal.lightning.today:443'
},
{
key: 'lnc.zeusln.app:443',
value: 'lnc.zeusln.app:443'
},
{ key: 'Custom defined mailbox', value: 'custom-defined' }
];
export const LOCALE_KEYS = [
{ key: 'en', value: 'English' },
{ key: 'es', value: 'Español' },
{ key: 'pt', value: 'Português' },
{ key: 'fr', value: 'Français' },
{ key: 'cs', value: 'Čeština' },
{ key: 'sk', value: 'Slovenčina' },
{ key: 'de', value: 'Deutsch' },
{ key: 'pl', value: 'Polski' },
{ key: 'tr', value: 'Türkçe' },
{ key: 'hu', value: 'magyar nyelv' },
{ key: 'zh', value: '简体中文' },
{ key: 'nl', value: 'Nederlands' },
{ key: 'nb', value: 'Bokmål' },
{ key: 'sv', value: 'Svenska' },
{ key: 'th', value: 'ภาษาไทย' },
{ key: 'uk', value: 'украї́нська мо́ва' },
{ key: 'ro', value: 'Limba română' },
{ key: 'el', value: 'Ελληνικά' },
{ key: 'fa', value: 'زبان فارسي' },
{ key: 'sl', value: 'Slovenski jezik' },
{ key: 'ru', value: 'русский язык' },
{ key: 'fi', value: 'Suomen kieli' },
{ key: 'it', value: 'Italiano' },
{ key: 'vi', value: 'Tiếng Việt' },
{ key: 'jp', value: '日本語' },
{ key: 'he', value: 'עִבְרִית' },
{ key: 'hr', value: 'Hrvatski' },
{ key: 'ko', value: '한국어' },
{ key: 'sw', value: 'Kiswahili' },
{ key: 'hi_IN', value: 'हिन्दी' },
{ key: 'zh_TW', value: '台灣華語' },
{ key: 'bg', value: 'Български' },
{ key: 'id', value: 'Bahasa Indonesia' }
];
// this mapping is only for migration and does not need to be updated when new languages are added
export const localeMigrationMapping: { [oldLocale: string]: string } = {
English: 'en',
Español: 'es',
Português: 'pt',
Français: 'fr',
Čeština: 'cs',
Slovenčina: 'sk',
Deutsch: 'de',
Polski: 'pl',
Türkçe: 'tr',
'magyar nyelv': 'hu',
简体中文: 'zh',
Nederlands: 'nl',
Bokmål: 'nb',
Svenska: 'sv',
ภาษาไทย: 'th',
'украї́нська мо́ва': 'uk',
'Limba română': 'ro',
Ελληνικά: 'el',
'زبان فارسي': 'fa',
'Slovenski jezik': 'sl',
'русский язык': 'ru',
'Suomen kieli': 'fi',
Italiano: 'it',
'Tiếng Việt': 'vi',
日本語: 'jp',
עִבְרִית: 'he',
Hrvatski: 'hr'
};
export const CURRENCY_KEYS = [
{
key: 'US Dollar',
value: 'USD',
flag: '🇺🇸',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Japanese Yen',
value: 'JPY',
flag: '🇯🇵',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Chinese Yuan',
value: 'CNY',
flag: '🇨🇳',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Singapore Dollar',
value: 'SGD',
flag: '🇸🇬',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Hong Kong Dollar',
value: 'HKD',
flag: '🇭🇰',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Canadian Dollar',
value: 'CAD',
flag: '🇨🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'New Zealand Dollar',
value: 'NZD',
flag: '🇳🇿',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Australian Dollar',
value: 'AUD',
flag: '🇦🇺',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Chilean Peso',
value: 'CLP',
flag: '🇨🇱',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Great British Pound',
value: 'GBP',
flag: '🇬🇧',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Danish Krone',
value: 'DKK',
flag: '🇩🇰',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Swedish Krona',
value: 'SEK',
flag: '🇸🇪',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Icelandic Krona',
value: 'ISK',
flag: '🇮🇸',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Swiss Franc',
value: 'CHF',
flag: '🇨🇭',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Brazilian Real',
value: 'BRL',
flag: '🇧🇷',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Eurozone Euro',
value: 'EUR',
flag: '🇪🇺',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Russian Ruble',
value: 'RUB',
flag: '🇷🇺',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Polish Złoty',
value: 'PLN',
flag: '🇵🇱',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Thai Baht',
value: 'THB',
flag: '🇹🇭',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'South Korean Won',
value: 'KRW',
flag: '🇰🇷',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'New Taiwan Dollar',
value: 'TWD',
flag: '🇹🇼',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Czech Koruna',
value: 'CZK',
flag: '🇨🇿',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Hungarian Forint',
value: 'HUF',
flag: '🇭🇺',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Indian Rupee',
value: 'INR',
flag: '🇮🇳',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Turkish Lira',
value: 'TRY',
flag: '🇹🇷',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Nigerian Naira',
value: 'NGN',
flag: '🇳🇬',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Argentine Peso',
value: 'ARS',
flag: '🇦🇷',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Israeli New Shekel',
value: 'ILS',
flag: '🇮🇱',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Lebanese Pound',
value: 'LBP',
flag: '🇱🇧',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Malaysian Ringgit',
value: 'MYR',
flag: '🇲🇾',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Ukrainian Hryvnia',
value: 'UAH',
flag: '🇺🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Jamaican Dollar',
value: 'JMD',
flag: '🇯🇲',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Colombian Peso',
value: 'COP',
flag: '🇨🇴',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Mexican Peso',
value: 'MXN',
flag: '🇲🇽',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Venezuelan Bolivar',
value: 'VES',
flag: '🇻🇪',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Tanzanian Shilling',
value: 'TZS',
flag: '🇹🇿',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Qatari Riyal',
value: 'QAR',
flag: '🇶🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Tunisian Dinar',
value: 'TND',
flag: '🇹🇳',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Norwegian Krone',
value: 'NOK',
flag: '🇳🇴',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'United Arab Emirates Dirham',
value: 'AED',
flag: '🇦🇪',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Trinidad & Tobago Dollar',
value: 'TTD',
flag: '🇹🇹',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Philippine Peso',
value: 'PHP',
flag: '🇵🇭',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Indonesian Rupiah',
value: 'IDR',
flag: '🇮🇩',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Romanian Leu',
value: 'RON',
flag: '🇷🇴',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Congolese Franc',
value: 'CDF',
flag: '🇨🇩',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Central African CFA franc',
value: 'XAF',
flag: '🇨🇲🇨🇫🇹🇩🇨🇬🇬🇶🇬🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'West African CFA franc',
value: 'XOF',
flag: '🇧🇯🇧🇫🇨🇮🇬🇼🇲🇱🇳🇪🇸🇳🇹🇬',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Kenyan Shilling',
value: 'KES',
flag: '🇰🇪',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Ugandan Shilling',
value: 'UGX',
flag: '🇺🇬',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'South African Rand',
value: 'ZAR',
flag: '🇿🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Cuban Peso',
value: 'CUP',
flag: '🇨🇺',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Dominican Peso',
value: 'DOP',
flag: '🇩🇴',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Belize Dollar',
value: 'BZD',
flag: '🇧🇿',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Bolivian Boliviano',
value: 'BOB',
flag: '🇧🇴',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Costa Rican Colón',
value: 'CRC',
flag: '🇨🇷',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Guatemalan Quetzal',
value: 'GTQ',
flag: '🇬🇹',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Nicaraguan Córdoba',
value: 'NIO',
flag: '🇳🇮',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Paraguayan Guaraní',
value: 'PYG',
flag: '🇵🇾',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Uruguayan Peso',
value: 'UYU',
flag: '🇺🇾',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Mauritanian Ouguiya',
value: 'MRU',
flag: '🇲🇷',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Albanian Lek',
value: 'ALL',
flag: '🇦🇱',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Netherlands Antillean Guilder',
value: 'ANG',
flag: '🇳🇱',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Angolan Kwanza',
value: 'AOA',
flag: '🇦🇴',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Bangladeshi Takka',
value: 'BDT',
flag: '🇧🇩',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Bulgarian Lev',
value: 'BGN',
flag: '🇧🇬',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Bahraini Dinar',
value: 'BHD',
flag: '🇧🇭',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Burundian Franc',
value: 'BIF',
flag: '🇧🇮',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Bermudan Dollar',
value: 'BMD',
flag: '🇧🇲',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Botswanan Pula',
value: 'BWP',
flag: '🇧🇼',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Djiboutian Franc',
value: 'DJF',
flag: '🇩🇯',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Algerian Dinar',
value: 'DZD',
flag: '🇩🇿',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Egyptian Pound',
value: 'EGP',
flag: '🇪🇬',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Ethiopian Birr',
value: 'ETB',
flag: '🇪🇹',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Georgian Lari',
value: 'GEL',
flag: '🇬🇪',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Ghanaian Cedi',
value: 'GHS',
flag: '🇬🇭',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Guinean Franc',
value: 'GNF',
flag: '🇬🇳',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Honduran Lempira',
value: 'HNL',
flag: '🇭🇳',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Iranian Rial',
value: 'IRR',
flag: '🇮🇷',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Jordanian Dinar',
value: 'JOD',
flag: '🇯🇴',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Kyrgystani Som',
value: 'KGS',
flag: '🇰🇬',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Kazakhstani Tenge',
value: 'KZT',
flag: '🇰🇿',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Sri Lankan Rupee',
value: 'LKR',
flag: '🇱🇰',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Moroccan Dirham',
value: 'MAD',
flag: '🇲🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Malagasy Ariar',
value: 'MGA',
flag: '🇲🇬',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Namibian Dollar',
value: 'NAD',
flag: '🇳🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Nepalese Rupee',
value: 'NPR',
flag: '🇳🇵',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Panamanian Balboa',
value: 'PAB',
flag: '🇵🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Peruvian Sol',
value: 'PEN',
flag: '🇵🇪',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Pakistani Rupee',
value: 'PKR',
flag: '🇵🇰',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Serbian Dinar',
value: 'RSD',
flag: '🇷🇸',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Rwandan Franc',
value: 'RWF',
flag: '🇷🇼',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Uzbekistani Sum',
value: 'UZS',
flag: '🇺🇿',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Vietnamese Dong',
value: 'VND',
flag: '🇻🇳',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Zambian Kwacha',
value: 'ZMW',
flag: '🇿🇲',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Malawian Kwacha',
value: 'MWK',
flag: '🇲🇼',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Lesotho Loti',
value: 'LSL',
flag: '🇱🇸',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Swazi Lilangeni',
value: 'SZL',
flag: '🇸🇿',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Saudi Riyal',
value: 'SAR',
flag: '🇸🇦',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Omani Rial',
value: 'OMR',
flag: '🇴🇲',
supportedSources: ['Zeus', 'Yadio']
},
// {
// key: 'Kuwaiti Dinar',
// value: 'KWD',
// flag: '🇰🇼',
// supportedSources: ['Zeus', 'Yadio']
// },
{
key: 'Gold',
value: 'XAU',
supportedSources: ['Zeus', 'Yadio']
},
{
key: 'Silver',
value: 'XAG',
supportedSources: ['Zeus', 'Yadio']
}
];
export const THEME_KEYS = [
{ key: 'Kyriaki', value: 'kyriaki' },
{ key: 'Dark', translateKey: 'views.Settings.Theme.dark', value: 'dark' },
{
key: 'Light',
translateKey: 'views.Settings.Theme.light',
value: 'light'
},
{
key: 'Junkie',
translateKey: 'views.Settings.Theme.junkie',
value: 'junkie'
},
{ key: 'BPM', translateKey: 'views.Settings.Theme.bpm', value: 'bpm' },
{
key: 'Blacked Out',
translateKey: 'views.Settings.Theme.blacked-out',
value: 'blacked-out'
},
{
key: 'Scarlet',
translateKey: 'views.Settings.Theme.scarlet',
value: 'scarlet'
},
{
key: 'Memberberry',
translateKey: 'views.Settings.Theme.purple',
value: 'purple'
},
{
key: 'Blueberry',
translateKey: 'views.Settings.Theme.blueberry',
value: 'blueberry'
},
{
key: 'Deep Purple',
translateKey: 'views.Settings.Theme.deep-purple',
value: 'deep-purple'
},
{
key: 'Deadpool',
translateKey: 'views.Settings.Theme.deadpool',
value: 'deadpool'
},
{
key: 'Mighty',
translateKey: 'views.Settings.Theme.mighty',
value: 'mighty'
},
{
key: 'Green',
translateKey: 'views.Settings.Theme.green',
value: 'green'
},
{ key: 'Pub', translateKey: 'views.Settings.Theme.pub', value: 'pub' },
{
key: 'Popsicle',
translateKey: 'views.Settings.Theme.popsicle',
value: 'popsicle'
},
{
key: 'Nostrich',
translateKey: 'views.Settings.Theme.nostrich',
value: 'nostrich'
},
{
key: 'Desert',
translateKey: 'views.Settings.Theme.desert',
value: 'desert'
},
{
key: 'Orange Cream Soda',
translateKey: 'views.Settings.Theme.orange-cream-soda',
value: 'orange-cream-soda'
},
{ key: 'Mint', translateKey: 'views.Settings.Theme.mint', value: 'mint' },
{
key: 'Red Metallic',
translateKey: 'views.Settings.Theme.red-metallic',
value: 'red-metallic'
},
{
key: 'Watermelon',
translateKey: 'views.Settings.Theme.watermelon',
value: 'watermelon'
},
{
key: 'Radioactive',
translateKey: 'views.Settings.Theme.radioactive',
value: 'radioactive'
},
{
key: 'Spooky',
translateKey: 'views.Settings.Theme.spooky',
value: 'orange'
}
];
export const DEFAULT_VIEW_KEYS = [
{
key: 'Balance',
translateKey: 'views.Settings.Display.DefaultView.balance',
value: 'Balance'
},
{
key: 'Keypad',
translateKey: 'views.Settings.Display.DefaultView.keypad',
value: 'Keypad'
}
];
export const DEFAULT_VIEW_KEYS_POS = [
{
key: 'Products',
translateKey: 'views.Settings.POS.Products',
value: 'Products'
},
{
key: 'POS Keypad',
translateKey: 'views.Settings.POS.Keypad',
value: 'POS Keypad'
}
];
export const DEFAULT_INVOICE_TYPE_KEYS = [
{
key: 'Unified',
translateKey: 'general.unified',
value: DefaultInvoiceType.Unified
},
{
key: 'Lightning',
translateKey: 'general.lightning',
value: DefaultInvoiceType.Lightning
}
];
export const DEFAULT_THEME = 'kyriaki';
export const DEFAULT_FIAT = 'USD';
export const DEFAULT_FIAT_RATES_SOURCE = 'Zeus';
export const DEFAULT_LOCALE = 'English';
export const POS_CONF_PREF_KEYS = [
{ key: '0 conf', translateKey: 'views.Settings.POS.0conf', value: '0conf' },
{ key: '1 conf', translateKey: 'views.Settings.POS.1conf', value: '1conf' },
{
key: 'LN only',
translateKey: 'views.Settings.POS.lnOnly',
value: 'lnOnly'
}
];
export const POS_ENABLED_KEYS = [
{
key: 'Disabled',
translateKey: 'general.disabled',
value: PosEnabled.Disabled
},
{
key: 'Standalone',
translateKey: 'views.Settings.POS.standalone',
value: PosEnabled.Standalone
},
{ key: 'Square', value: PosEnabled.Square }
];
export const LNDHUB_AUTH_MODES = [
{ key: 'BlueWallet', value: 'BlueWallet' },
{ key: 'Alby', value: 'Alby' }
];
export const DEFAULT_LSP_MAINNET = 'https://0conf.lnolymp.us';
export const DEFAULT_LSP_TESTNET = 'https://testnet-0conf.lnolymp.us';
// LSPS1 REST
export const DEFAULT_LSPS1_REST_MAINNET = 'https://lsps1.lnolymp.us';
export const DEFAULT_LSPS1_REST_TESTNET = 'https://testnet-lsps1.lnolymp.us';
export const DEFAULT_LSPS1_PUBKEY_MAINNET =
'031b301307574bbe9b9ac7b79cbe1700e31e544513eae0b5d7497483083f99e581';
export const DEFAULT_LSPS1_PUBKEY_TESTNET =
'03e84a109cd70e57864274932fc87c5e6434c59ebb8e6e7d28532219ba38f7f6df';
export const DEFAULT_LSPS1_HOST_MAINNET = '45.79.192.236:9735';
export const DEFAULT_LSPS1_HOST_TESTNET = '139.144.22.237:9735';
export const DEFAULT_LSP_MUTINYNET = 'https://mutinynet-flow.lnolymp.us';
export const DEFAULT_LSPS1_REST_MUTINYNET =
'https://mutinynet-lsps1.lnolymp.us';
export const DEFAULT_LSPS1_PUBKEY_MUTINYNET =
'032ae843e4d7d177f151d021ac8044b0636ec72b1ce3ffcde5c04748db2517ab03';
export const DEFAULT_LSPS1_HOST_MUTINYNET = '45.79.201.241:9735';
/**
* Select LSP config values for a given network.
* Accepts either a network string ('mainnet'|'testnet'|'signet'|'mutinynet')
* or NodeInfo-style flags ({ isMutinynet, isTestNet }).
*/
export function getLspConfigForNetwork(
settings: Settings,
network: string | { isMutinynet: boolean; isTestNet: boolean }
): {
flowHost: string;
lsps1Rest: string;
lsps1Pubkey: string;
lsps1Host: string;
defaultPubkey: string;
} {
const isMutinynet =
typeof network === 'string'
? network === 'mutinynet'
: network.isMutinynet;
const isTestnet =
typeof network === 'string'
? network === 'testnet' || network === 'signet'
: network.isTestNet;
if (isMutinynet) {
return {
flowHost: settings.lspMutinynet || DEFAULT_LSP_MUTINYNET,
lsps1Rest:
settings.lsps1RestMutinynet || DEFAULT_LSPS1_REST_MUTINYNET,
lsps1Pubkey:
settings.lsps1PubkeyMutinynet || DEFAULT_LSPS1_PUBKEY_MUTINYNET,
lsps1Host:
settings.lsps1HostMutinynet || DEFAULT_LSPS1_HOST_MUTINYNET,
defaultPubkey: DEFAULT_LSPS1_PUBKEY_MUTINYNET
};
}
if (isTestnet) {
return {
flowHost: settings.lspTestnet || DEFAULT_LSP_TESTNET,
lsps1Rest: settings.lsps1RestTestnet || DEFAULT_LSPS1_REST_TESTNET,
lsps1Pubkey:
settings.lsps1PubkeyTestnet || DEFAULT_LSPS1_PUBKEY_TESTNET,
lsps1Host: settings.lsps1HostTestnet || DEFAULT_LSPS1_HOST_TESTNET,
defaultPubkey: DEFAULT_LSPS1_PUBKEY_TESTNET
};
}
return {
flowHost: settings.lspMainnet || DEFAULT_LSP_MAINNET,
lsps1Rest: settings.lsps1RestMainnet || DEFAULT_LSPS1_REST_MAINNET,
lsps1Pubkey:
settings.lsps1PubkeyMainnet || DEFAULT_LSPS1_PUBKEY_MAINNET,
lsps1Host: settings.lsps1HostMainnet || DEFAULT_LSPS1_HOST_MAINNET,
defaultPubkey: DEFAULT_LSPS1_PUBKEY_MAINNET
};
}
// Swaps
export const DEFAULT_SWAP_HOST_MAINNET = 'https://swaps.zeuslsp.com/api/v2';
export const DEFAULT_SWAP_HOST_TESTNET =
'https://testnet-swaps.zeuslsp.com/api/v2';
export const DEFAULT_NOSTR_RELAYS_2023 = [
'wss://nostr.mutinywallet.com',
'wss://relay.damus.io',
'wss://nostr.lnproxy.org'
];
export const DEFAULT_NOSTR_RELAYS = [
'wss://nos.lol',
'wss://relay.snort.social',
'wss://relay.getalby.com/v1',
'wss://relay.damus.io',
'wss://nostr.land',
'wss://nostr.wine',
'wss://relay.8333.space',
'wss://relay.primal.net'
];
export const NOTIFICATIONS_PREF_KEYS = [
{ key: 'Disabled', translateKey: 'general.disabled', value: 0 },
{
key: 'Push',
translateKey:
'views.Settings.LightningAddressSettings.notifications.push',
value: 1
},
{
key: 'Nostr',
value: 2
}
];
export const AUTOMATIC_ATTESTATION_KEYS = [
{ key: 'Disabled', translateKey: 'general.disabled', value: 0 },
{
key: 'Successful only',
translateKey:
'views.Settings.LightningAddressSettings.automaticallyAcceptAttestationLevel.successOnly',
value: 1
},
{
key: 'Successful and not found',
translateKey:
'views.Settings.LightningAddressSettings.automaticallyAcceptAttestationLevel.successAndNotFound',
value: 2
}
];
export const TIME_PERIOD_KEYS = [
{ key: 'Seconds', translateKey: 'time.seconds', value: 'Seconds' },
{ key: 'Minutes', translateKey: 'time.minutes', value: 'Minutes' },
{ key: 'Hours', translateKey: 'time.hours', value: 'Hours' },
{ key: 'Days', translateKey: 'time.days', value: 'Days' },
{ key: 'Weeks', translateKey: 'time.weeks', value: 'Weeks' }
];
export const DEFAULT_NEUTRINO_PEERS_MAINNET = [
'btcd1.lnolymp.us',
'btcd2.lnolymp.us',
'btcd-mainnet.lightning.computer',
'node.eldamar.icu',
'noad.sathoarder.com'
];
export const SECONDARY_NEUTRINO_PEERS_MAINNET = [
// friends
[
'uswest.blixtwallet.com',
'europe.blixtwallet.com',
'bb1.breez.technology',
'bb2.breez.technology'
],
// Asia
[
'sg.lnolymp.us',
'asia.blixtwallet.com',
// per Expatriotic
'168.159.213.bc.googleusercontent.com',
'115.85.88.107',
'182.229.145.161',
'18.142.108.45'
]
];
export const DEFAULT_NEUTRINO_PEERS_TESTNET = [
'testnet.lnolymp.us',
'btcd-testnet.lightning.computer',
'testnet.blixtwallet.com'
];
export const DEFAULT_SLIDE_TO_PAY_THRESHOLD = 10000;
export default class SettingsStore {
@observable settings: Settings = {
privacy: {
defaultBlockExplorer: 'mempool.space',
customBlockExplorer: '',
clipboard: true,
lurkerMode: false,
enableMempoolRates: true,
stealthMode: false,
stealthApp: 'calculator',
stealthPinLength: 5,
stealthVpnCountry: 'Switzerland',
stealthVpnServer: 'Geneva'
},
display: {
theme: DEFAULT_THEME,
defaultView: 'Keypad',
displayNickname: false,
bigKeypadButtons: false,
showAllDecimalPlaces: false,
removeDecimalSpaces: false,
showMillisatoshiAmounts: false
},
pos: {
posEnabled: PosEnabled.Disabled,
squareEnabled: false, // deprecated
squareAccessToken: '',
squareLocationId: '',
merchantName: '',
confirmationPreference: 'lnOnly',
disableTips: false,
squareDevMode: false,
showKeypad: true,
taxPercentage: '',
enablePrinter: false,
defaultView: 'Products'
},
payments: {
defaultFeeMethod: 'fixed', // deprecated
defaultFeePercentage: '5.0',
defaultFeeFixed: '1000',
timeoutSeconds: '60',
preferredMempoolRate: 'fastestFee',
slideToPayThreshold: DEFAULT_SLIDE_TO_PAY_THRESHOLD,
enableDonations: false,
defaultDonationPercentage: 5
},
invoices: {
addressType: '0',
memo: '',
receiverName: '',
expiry: '1',
timePeriod: 'Hours',
expirySeconds: '3600',
routeHints: false,
ampInvoice: false,
blindedPaths: false,
showCustomPreimageField: false,
displayAmountOnInvoice: false, // deprecated
defaultInvoiceType: DefaultInvoiceType.Lightning
},
channels: {
min_confs: 1,
privateChannel: true,
scidAlias: true,
simpleTaprootChannel: false
},
supportedBiometryType: undefined,
isBiometryEnabled: false,
scramblePin: true,
loginBackground: false,
fiatEnabled: true,
fiat: DEFAULT_FIAT,
fiatRatesSource: DEFAULT_FIAT_RATES_SOURCE,
// embedded node
automaticDisasterRecoveryBackup: true,
expressGraphSync: false,
resetExpressGraphSyncOnStartup: false,
bimodalPathfinding: true,
graphSyncPromptNeverAsk: false,
graphSyncPromptIgnoreOnce: false,
dontAllowOtherPeers: false,
neutrinoPeersMainnet: DEFAULT_NEUTRINO_PEERS_MAINNET,
neutrinoPeersTestnet: DEFAULT_NEUTRINO_PEERS_TESTNET,
zeroConfPeers: [],
rescan: false,
compactDb: false,
recovery: false,
initialLoad: true,
embeddedTor: false,
feeEstimator: DEFAULT_FEE_ESTIMATOR,
customFeeEstimator: '',
speedloader: DEFAULT_SPEEDLOADER,
customSpeedloader: '',
// LSP
enableLSP: true,
lspMainnet: DEFAULT_LSP_MAINNET,
lspTestnet: DEFAULT_LSP_TESTNET,
lspMutinynet: DEFAULT_LSP_MUTINYNET,
lspAccessKey: '',
requestSimpleTaproot: true,
//lsps1
lsps1RestMainnet: DEFAULT_LSPS1_REST_MAINNET,
lsps1RestTestnet: DEFAULT_LSPS1_REST_TESTNET,
lsps1RestMutinynet: DEFAULT_LSPS1_REST_MUTINYNET,
lsps1PubkeyMainnet: DEFAULT_LSPS1_PUBKEY_MAINNET,
lsps1PubkeyTestnet: DEFAULT_LSPS1_PUBKEY_TESTNET,
lsps1PubkeyMutinynet: DEFAULT_LSPS1_PUBKEY_MUTINYNET,
lsps1HostMainnet: DEFAULT_LSPS1_HOST_MAINNET,
lsps1HostTestnet: DEFAULT_LSPS1_HOST_TESTNET,
lsps1HostMutinynet: DEFAULT_LSPS1_HOST_MUTINYNET,
lsps1Token: '',
//swaps
swaps: {
hostMainnet: DEFAULT_SWAP_HOST_MAINNET,
hostTestnet: DEFAULT_SWAP_HOST_TESTNET,
customHost: '',
proEnabled: false
},
// Lightning Address
lightningAddress: {
enabled: false,
automaticallyAccept: true,
automaticallyAcceptAttestationLevel: 2,
automaticallyRequestOlympusChannels: false, // deprecated
routeHints: false,
allowComments: true,
zapReceiptsEnabled: true,
nostrPrivateKey: '',
nostrRelays: DEFAULT_NOSTR_RELAYS,
notifications: 0,
mintUrl: '',
posEnabled: false // ZEUS Pay+
},
bolt12Address: {
localPart: ''
},
ecash: {
enableCashu: false,
enableMultiMint: false,
automaticallySweep: false,
sweepThresholdSats: 10000
},
networking: {
disableOfflineCheck: false
},
selectNodeOnStartup: false
};
@observable public posStatus: string = 'unselected';
@observable public posWasEnabled: boolean = false;
@observable public loading = false;
@observable public isMigrating = false;
@observable public settingsUpdateInProgress: boolean = false;
@observable btcPayError: string | null;
@observable sponsorsError: string | null;
@observable olympians: Array<any> = [];
@observable gods: Array<any> = [];
@observable mortals: Array<any> = [];
@observable host: string;
@observable port: string;
@observable url: string;
@observable macaroonHex: string;
@observable rune: string;
@observable accessKey: string;
@observable implementation: Implementations;
@observable certVerification: boolean = false;
@observable public loggedIn = false;
@observable public triggerSettingsRefresh: boolean = false;
@observable public connecting = true;
@observable public fetchLock = false;
@observable public lurkerExposed = false;
private lurkerTimeout: ReturnType<typeof setTimeout> | null = null;
// LNDHub
@observable username: string;
@observable password: string;
@observable lndhubUrl: string;
@observable dismissCustodialWarning: boolean = false;
@observable public createAccountError: string;
@observable public createAccountSuccess: string;
@observable public accessToken: string;
@observable public refreshToken: string;
// Tor
@observable public enableTor: boolean;
// LNC
@observable public pairingPhrase: string;
@observable public mailboxServer: string;
@observable public customMailboxServer: string;
@observable public error = false;
@observable public errorMsg: string;
// Embedded lnd
@observable public seedPhrase: Array<string>;
@observable public walletPassword: string;
@observable public adminMacaroon: string;
@observable public embeddedLndNetwork: string;
@observable public lndDir?: string;
@observable public isSqlite?: boolean;
@observable public initialStart: boolean = true;
@observable public embeddedLndStarted: boolean = false;
@observable public walletJustCreated: boolean = false;
@observable public lndFolderMissing: boolean = false;
// Embedded LDK Node
@observable public ldkNodeDir?: string;
@observable public ldkMnemonic?: string;
@observable public ldkPassphrase?: string;
@observable public ldkNetwork?: string;
@observable public ldkEsploraServer?: string;
@observable public ldkRgsServer?: string;
@observable public ldkScorerUrl?: string;
@observable public ldkVssServer?: string;
@observable public ldkNodeSyncing: boolean = false;
@observable public isChannelMigrating: boolean = false;
// NWC
@observable public nostrWalletConnectUrl: string;
// Favorite currencies
@observable public favoriteCurrencies: string[] = [];
@action
public loadFavoriteCurrencies = async () => {
try {
const stored = await Storage.getItem(FAVORITE_CURRENCIES_KEY);
if (stored) {
runInAction(() => {
this.favoriteCurrencies = JSON.parse(stored);
});
}
} catch (e) {
console.error('Error loading favorite currencies:', e);
}
};
@action
public toggleFavoriteCurrency = async (currencyCode: string) => {
const favorites = new Set(this.favoriteCurrencies);
if (favorites.has(currencyCode)) {
favorites.delete(currencyCode);
} else {
favorites.add(currencyCode);
}
this.favoriteCurrencies = Array.from(favorites);
await Storage.setItem(
FAVORITE_CURRENCIES_KEY,
JSON.stringify(this.favoriteCurrencies)
);
};
public setInitialStart = (status: boolean) => {
this.initialStart = status;
};
public setLndFolderMissing = (status: boolean) => {
this.lndFolderMissing = status;
};
@action
public setChannelMigrating = (status: boolean) => {
this.isChannelMigrating = status;
};
public fetchBTCPayConfig = (data: string) => {
const configRoute = data.split('config=')[1];
this.btcPayError = null;
if (configRoute.includes('.onion')) {
return doTorRequest(configRoute, RequestMethod.GET)
.then((response: any) => this.parseBTCPayConfig(response))
.catch((err: any) => {
this.btcPayError = `${localeString(
'stores.SettingsStore.btcPayFetchConfigError'
)}: ${err.toString()}`;
});
} else {
return ReactNativeBlobUtil.fetch('get', configRoute)
.then((response: any) => {
const status = response.info().status;
if (status == 200) {
const data = response.json();
return this.parseBTCPayConfig(data);
} else {
this.btcPayError = localeString(
'stores.SettingsStore.btcPayFetchConfigError'
);
}
})
.catch((err: any) => {
this.btcPayError = `${localeString(
'stores.SettingsStore.btcPayFetchConfigError'
)}: ${err.toString()}`;
});
}
};
@action
public fetchSponsors = () => {
const olympiansRoute = 'https://zeusln.com/api/sponsors/v2/getSponsors';
this.sponsorsError = null;
this.olympians = [];
this.gods = [];
this.mortals = [];
this.loading = true;
if (this.enableTor) {
return doTorRequest(olympiansRoute, RequestMethod.GET)
.then((response: any) => {
runInAction(() => {
this.olympians = response.olympians;
this.gods = response.gods;
this.mortals = response.mortals;
this.loading = false;
});
})
.catch((err: any) => {
runInAction(() => {
this.olympians = [];
this.gods = [];
this.mortals = [];
this.loading = false;
this.sponsorsError = `${localeString(
'stores.SettingsStore.olympianFetchError'
)}: ${err.toString()}`;
});
});
} else {
return ReactNativeBlobUtil.fetch('get', olympiansRoute)
.then((response: any) => {
const status = response.info().status;
runInAction(() => {
if (status == 200) {
const data = response.json();
this.olympians = data.olympians;
this.gods = data.gods;
this.mortals = data.mortals;
this.loading = false;
} else {
this.olympians = [];
this.gods = [];
this.mortals = [];
this.loading = false;
this.sponsorsError = localeString(
'stores.SettingsStore.olympianFetchError'
);
}
});
})
.catch((err: any) => {
runInAction(() => {
this.olympians = [];
this.gods = [];
this.mortals = [];
this.loading = false;
this.sponsorsError = `${localeString(
'stores.SettingsStore.olympianFetchError'
)}: ${err.toString()}`;
});
});
}
};
private parseBTCPayConfig(data: any) {
const configuration = data.configurations[0];
const { adminMacaroon, macaroon, type, uri } = configuration;
if (type !== 'lnd-rest') {
this.btcPayError = localeString(
'stores.SettingsStore.btcPayImplementationSupport'
);
} else {
const config = {
host: uri,
macaroonHex: adminMacaroon || macaroon,
implementation: 'lnd'
};
return config;
}
}
public hasCredentials() {
return this.macaroonHex || this.accessKey ? true : false;
}
@action
private updateNodeProperties = (settings: Settings) => {
const node: any =
settings?.nodes?.length &&
settings?.nodes[settings.selectedNode || 0];
if (node) {
this.host = node.host;
this.port = node.port;
this.url = node.url;
this.username = node.username;
this.password = node.password;
this.lndhubUrl = node.lndhubUrl;
this.macaroonHex = node.macaroonHex;
this.rune = node.rune;
this.accessKey = node.accessKey;
this.dismissCustodialWarning = node.dismissCustodialWarning;
this.implementation = node.implementation || 'lnd';
this.certVerification = node.certVerification || false;
this.enableTor = node.enableTor;
// LNC
this.pairingPhrase = node.pairingPhrase;
this.mailboxServer = node.mailboxServer;
this.customMailboxServer = node.customMailboxServer;
// Embedded lnd
this.seedPhrase = node.seedPhrase;
this.walletPassword = node.walletPassword;
this.adminMacaroon = node.adminMacaroon;
this.embeddedLndNetwork = node.embeddedLndNetwork;
this.lndDir = node.lndDir || 'lnd';
this.isSqlite = node.isSqlite;
// Embedded LDK Node
this.ldkNodeDir = node.ldkNodeDir;
this.ldkMnemonic = node.ldkMnemonic;
this.ldkPassphrase = node.ldkPassphrase;
this.ldkNetwork = node.ldkNetwork;
this.ldkEsploraServer =
node.ldkEsploraServer ||
getDefaultEsploraServer(
(node.ldkNetwork?.toLowerCase() as SupportedNetwork) ||
'mainnet'
);
this.ldkRgsServer =
node.ldkRgsServer ||
getDefaultRgsServer(
(node.ldkNetwork?.toLowerCase() as SupportedNetwork) ||
'mainnet'
);
this.ldkScorerUrl = node.ldkScorerUrl || DEFAULT_SCORER_URL;
this.ldkVssServer = node.ldkVssServer || DEFAULT_VSS_SERVER;
// NWC
this.nostrWalletConnectUrl = node.nostrWalletConnectUrl;
} else {
// No node selected — clear all node properties to prevent
// stale references to deleted wallets
this.implementation = 'lnd';
this.certVerification = false;
this.ldkNodeDir = undefined;
this.ldkMnemonic = undefined;
this.ldkPassphrase = undefined;
this.ldkNetwork = undefined;
this.ldkEsploraServer = undefined;
this.ldkRgsServer = undefined;
this.ldkScorerUrl = undefined;
this.ldkVssServer = undefined;
}
};
public getSettings = async (silentUpdate: boolean = false) => {
if (!silentUpdate) this.loading = true;
try {
await MigrationsUtils.keychainCloudSyncMigration();
const modernSettings: any = await Storage.getItem(STORAGE_KEY);
if (modernSettings) {
console.log('attempting to load modern settings');
const parsedSettings = JSON.parse(modernSettings);
this.settings = parsedSettings;
await MigrationsUtils.migrateRgsDefaultToZeus(parsedSettings);
await MigrationsUtils.migrateInvoiceExpiryDisplay(
parsedSettings
);
this.settings = parsedSettings;
} else {
console.log('attempting to load legacy settings');
// Retrieve the settings
const settings = await EncryptedStorage.getItem(
LEGACY_STORAGE_KEY
);
if (settings) {
const newSettings =
await MigrationsUtils.legacySettingsMigrations(
settings
);
if (!isEqual(this.settings, newSettings)) {
this.settings = newSettings;
}
await MigrationsUtils.storageMigrationV2(newSettings);
} else {
console.log('No legacy settings stored');
}
}
this.updateNodeProperties(this.settings);
} catch (error) {
console.error('Could not load settings', error);
} finally {
this.isMigrating = false;
if (!silentUpdate) this.loading = false;
}
return this.settings;
};
public async setSettings(settings: any) {
this.loading = true;
await Storage.setItem(STORAGE_KEY, settings);
this.settings = settings;
this.loading = false;
return settings;
}
public updateSettings = async (newSetting: any) => {
this.settingsUpdateInProgress = true;
const existingSettings = await this.getSettings();
const newSettings = {
...existingSettings,
...newSetting
};
if (
newSetting.pos?.posEnabled &&
newSetting.pos.posEnabled !== PosEnabled.Disabled
) {
this.posWasEnabled = true;
}
await this.setSettings(newSettings);
this.triggerSettingsRefresh = true;
// Update store's node properties from latest settings
this.updateNodeProperties(newSettings);
this.settingsUpdateInProgress = false;
return newSettings;
};
// LNDHub
@action
public createAccount = (
host: string,
certVerification: boolean,
enableTor?: boolean
) => {
const url = `${host}/create`;
const headers = {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
};
this.createAccountSuccess = '';
this.createAccountError = '';
this.loading = true;
if (enableTor) {
return doTorRequest(url, RequestMethod.POST)
.then((response: any) => {
runInAction(() => {
this.loading = false;
if (response.error) {
this.createAccountError =
response.message ||
localeString(
'stores.SettingsStore.lndhubError'
);
} else {
this.createAccountSuccess = localeString(
'stores.SettingsStore.lndhubSuccess'
);
}
});
return response;
})
.catch((err: any) => {
const errorString = err.error || err.toString();
runInAction(() => {
this.loading = false;
this.createAccountError = `${localeString(
'stores.SettingsStore.lndhubError'
)}: ${errorString}`;
});
});
} else {
return ReactNativeBlobUtil.config({
trusty: !certVerification
})
.fetch('post', url, headers, '')
.then((response: any) => {
const status = response.info().status;
if (status == 200) {
const data = response.json();
runInAction(() => {
this.loading = false;
if (data.error) {
this.createAccountError =
data.message ||
localeString(
'stores.SettingsStore.lndhubError'
);
} else {
this.createAccountSuccess = localeString(
'stores.SettingsStore.lndhubSuccess'
);
}
});
return data;
} else {
runInAction(() => {
this.loading = false;
this.createAccountError = localeString(
'stores.SettingsStore.lndhubError'
);
});
}
})
.catch((err: any) => {
const errorString = err.error || err.toString();
runInAction(() => {
this.loading = false;
this.createAccountError = `${localeString(
'stores.SettingsStore.lndhubError'
)}: ${errorString}`;
});
});
}
};
// LNDHub
@action
public login = (request: LoginRequest) => {
this.error = false;
this.errorMsg = '';
this.createAccountSuccess = '';
this.createAccountError = '';
this.loading = true;
return new Promise<void>(async (resolve) => {
await BackendUtils.login({
login: request.login,
password: request.password
})
.then((data: any) => {
runInAction(() => {
this.loading = false;
this.accessToken = data.access_token;
this.refreshToken = data.refresh_token;
});
resolve(data);
})
.catch((error: any) => {
runInAction(() => {
this.loading = false;
this.error = true;
if (
typeof error.message === 'string' &&
error.message.includes('"bad auth"')
) {
this.errorMsg = localeString(
'stores.SettingsStore.lndhubLoginError'
);
} else {
this.errorMsg = localeString(
'stores.SettingsStore.lndhubConnectError'
);
}
});
resolve();
});
});
};
// LNC
public connect = async () => {
this.loading = true;
await BackendUtils.initLNC();
const error = await BackendUtils.connect();
if (error) {
runInAction(() => {
this.error = true;
this.errorMsg = error;
});
return error;
}
// repeatedly check if the connection was successful
return new Promise<string | void>((resolve) => {
let counter = 0;
const interval = setInterval(async () => {
counter++;
const connected = await BackendUtils.isConnected();
if (connected) {
clearInterval(interval);
this.loading = false;
resolve();
} else if (counter > 20) {
clearInterval(interval);
runInAction(() => {
this.error = true;
this.errorMsg = localeString(
'stores.SettingsStore.lncConnectError'
);
this.loading = false;
});
resolve(this.errorMsg);
}
}, 500);
});
};
// NWC
@action
public connectNWC = async () => {
this.loading = true;
await BackendUtils.initNWC();
const error = await BackendUtils.connect();
if (error) {
this.error = true;
this.errorMsg = error;
return error;
}
this.loading = false;
};
public loginRequired = () => this.loginMethodConfigured() && !this.loggedIn;
public loginMethodConfigured = () =>
this.settings &&
(this.settings.passphrase ||
this.settings.pin ||
this.isBiometryConfigured());
public checkBiometricsStatus = async () => {
const biometryType = await getSupportedBiometryType();
if (this.settings.supportedBiometryType !== biometryType) {
await this.updateSettings({
supportedBiometryType: biometryType
});
}
return {
supportedBiometryType: biometryType,
isBiometryEnabled: this.settings.isBiometryEnabled
};
};
public isBiometryConfigured = () =>
this.settings != null &&
this.settings.isBiometryEnabled &&
this.settings.supportedBiometryType !== undefined;
public setLoginStatus = (status = false) => (this.loggedIn = status);
@action
public setConnectingStatus = (status = false) => {
// reset error on reconnect
if (status) {
this.error = false;
this.errorMsg = '';
this.lndFolderMissing = false;
BackendUtils.clearCachedCalls();
// remove fetchLock on reconnect
this.fetchLock = false;
}
this.connecting = status;
return this.connecting;
};
@action
public toggleLurker = () => {
if (this.lurkerTimeout) {
clearTimeout(this.lurkerTimeout);
}
this.lurkerExposed = true;
this.settings.privacy.lurkerMode = false;
this.lurkerTimeout = setTimeout(() => {
this.lurkerExposed = false;
this.settings.privacy.lurkerMode = true;
this.lurkerTimeout = null;
}, 3000);
};
public setPosStatus = (setting: string) => {
this.posStatus = setting;
return this.posStatus;
};
}