├── .gitattributes ├── .github └── workflows │ └── testnet-build.yml ├── .gitignore ├── .langtool ├── config.json ├── timestamps.android.json └── timestamps.ios.json ├── .readme └── phoenix_text.png ├── BUILD.md ├── Dockerfile ├── LICENSE ├── README.md ├── TRANSLATION.md ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties.template ├── phoenix-android ├── TRANSLATION.md ├── build.gradle.kts ├── google-services.json ├── proguard-rules.pro └── src │ ├── androidTest │ └── kotlin │ │ └── fr │ │ └── acinq │ │ └── phoenix │ │ └── utils │ │ └── ConverterTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── kotlin │ │ └── fr │ │ │ └── acinq │ │ │ └── phoenix │ │ │ └── android │ │ │ ├── Ambients.kt │ │ │ ├── AppView.kt │ │ │ ├── AppViewModel.kt │ │ │ ├── MainActivity.kt │ │ │ ├── Navigation.kt │ │ │ ├── NoticesViewModel.kt │ │ │ ├── PaymentsViewModel.kt │ │ │ ├── PhoenixApplication.kt │ │ │ ├── components │ │ │ ├── AmountHeroInput.kt │ │ │ ├── AmountInput.kt │ │ │ ├── AmountView.kt │ │ │ ├── Buttons.kt │ │ │ ├── CalendarView.kt │ │ │ ├── Card.kt │ │ │ ├── Checkbox.kt │ │ │ ├── FeerateSlider.kt │ │ │ ├── Inputs.kt │ │ │ ├── Layout.kt │ │ │ ├── MenuButton.kt │ │ │ ├── ProgressView.kt │ │ │ ├── SatoshiLogSlider.kt │ │ │ ├── SatoshiSlider.kt │ │ │ ├── SplashLayout.kt │ │ │ ├── Switch.kt │ │ │ ├── auth │ │ │ │ ├── pincode │ │ │ │ │ ├── CheckPinFlow.kt │ │ │ │ │ ├── CheckPinViewModel.kt │ │ │ │ │ ├── NewPinView.kt │ │ │ │ │ ├── NewPinViewModel.kt │ │ │ │ │ ├── PinDialog.kt │ │ │ │ │ └── PinKeyboard.kt │ │ │ │ ├── screenlock │ │ │ │ │ ├── CheckScreenLockPinView.kt │ │ │ │ │ ├── CheckScreenLockPinViewModel.kt │ │ │ │ │ ├── NewScreenLockPinFlow.kt │ │ │ │ │ ├── NewScreenLockPinViewModel.kt │ │ │ │ │ └── ScreenLockPrompt.kt │ │ │ │ └── spendinglock │ │ │ │ │ ├── CheckSpendingPinView.kt │ │ │ │ │ ├── CheckSpendingPinViewModel.kt │ │ │ │ │ ├── NewSpendingPinView.kt │ │ │ │ │ └── NewSpendingPinViewModel.kt │ │ │ ├── buttons │ │ │ │ ├── AnimatedSegmentedButton.kt │ │ │ │ └── SmartSpendButton.kt │ │ │ ├── contact │ │ │ │ ├── ContactCompactView.kt │ │ │ │ ├── ContactDetailsView.kt │ │ │ │ ├── ContactOrOfferView.kt │ │ │ │ ├── ContactPhotoView.kt │ │ │ │ └── ContactsListView.kt │ │ │ ├── dialogs │ │ │ │ ├── BasicDialog.kt │ │ │ │ ├── BottomSheetDialog.kt │ │ │ │ ├── ConfirmDialog.kt │ │ │ │ ├── FullScreenDialog.kt │ │ │ │ └── Popup.kt │ │ │ ├── feedback │ │ │ │ ├── ErrorMessage.kt │ │ │ │ ├── FeedbackMessage.kt │ │ │ │ ├── InfoMessage.kt │ │ │ │ ├── SuccessMessage.kt │ │ │ │ └── WarningMessage.kt │ │ │ ├── mvi │ │ │ │ ├── MVIControllerViewModel.kt │ │ │ │ └── MVIView.kt │ │ │ ├── nfc │ │ │ │ ├── HceMonitor.kt │ │ │ │ ├── NfcReaderMonitor.kt │ │ │ │ └── NfcState.kt │ │ │ ├── scanner │ │ │ │ └── ScannerView.kt │ │ │ └── settings │ │ │ │ ├── Preferences.kt │ │ │ │ ├── SettingSwitch.kt │ │ │ │ └── Settings.kt │ │ │ ├── home │ │ │ ├── ConnectionDialog.kt │ │ │ ├── HomeBalance.kt │ │ │ ├── HomeNotices.kt │ │ │ ├── HomePayments.kt │ │ │ ├── HomeTopAndBottom.kt │ │ │ ├── HomeView.kt │ │ │ └── releasenotes │ │ │ │ └── ReleaseNotesDialog.kt │ │ │ ├── initwallet │ │ │ ├── InitView.kt │ │ │ ├── InitViewModel.kt │ │ │ ├── create │ │ │ │ └── CreateWalletView.kt │ │ │ └── restore │ │ │ │ ├── DisclaimerView.kt │ │ │ │ ├── RestorePaymentsDbButton.kt │ │ │ │ ├── RestoreWalletView.kt │ │ │ │ ├── RestoreWalletViewModel.kt │ │ │ │ └── SeedInputView.kt │ │ │ ├── intro │ │ │ └── IntroView.kt │ │ │ ├── payments │ │ │ ├── details │ │ │ │ ├── PaymentDetailsView.kt │ │ │ │ ├── PaymentLine.kt │ │ │ │ ├── PaymentSplashView.kt │ │ │ │ ├── PaymentTechnicalView.kt │ │ │ │ ├── splash │ │ │ │ │ ├── SplashAmount.kt │ │ │ │ │ ├── SplashDescription.kt │ │ │ │ │ ├── SplashIncomingBolt11.kt │ │ │ │ │ ├── SplashIncomingBolt12.kt │ │ │ │ │ ├── SplashIncomingLegacyPayToOpen.kt │ │ │ │ │ ├── SplashIncomingLegacySwapIn.kt │ │ │ │ │ ├── SplashIncomingNewChannel.kt │ │ │ │ │ ├── SplashIncomingOnChain.kt │ │ │ │ │ ├── SplashOutgoingAutoLiquidityPurchase.kt │ │ │ │ │ ├── SplashOutgoingChannelClose.kt │ │ │ │ │ ├── SplashOutgoingLightning.kt │ │ │ │ │ ├── SplashOutgoingManualLiquidityPurchase.kt │ │ │ │ │ ├── SplashOutgoingSplice.kt │ │ │ │ │ ├── SplashOutgoingSpliceCpfp.kt │ │ │ │ │ └── SplashStatus.kt │ │ │ │ └── technical │ │ │ │ │ ├── TechnicalIncomingBolt11.kt │ │ │ │ │ ├── TechnicalIncomingBolt12.kt │ │ │ │ │ ├── TechnicalIncomingLegacyPayToOpen.kt │ │ │ │ │ ├── TechnicalIncomingLegacySwapIn.kt │ │ │ │ │ ├── TechnicalIncomingNewChannel.kt │ │ │ │ │ ├── TechnicalIncomingSpliceIn.kt │ │ │ │ │ ├── TechnicalOutgoingClose.kt │ │ │ │ │ ├── TechnicalOutgoingLightning.kt │ │ │ │ │ ├── TechnicalOutgoingLiquidityAuto.kt │ │ │ │ │ ├── TechnicalOutgoingLiquidityManual.kt │ │ │ │ │ ├── TechnicalOutgoingSplice.kt │ │ │ │ │ └── TechnicalOutgoingSpliceCpfp.kt │ │ │ ├── history │ │ │ │ ├── PaymentsExportView.kt │ │ │ │ ├── PaymentsExportViewModel.kt │ │ │ │ └── PaymentsHistoryView.kt │ │ │ ├── receive │ │ │ │ ├── ReceiveBaseView.kt │ │ │ │ ├── ReceiveLightningView.kt │ │ │ │ ├── ReceiveOnChainView.kt │ │ │ │ └── ReceiveViewModel.kt │ │ │ └── send │ │ │ │ ├── PrepareSendSmartInput.kt │ │ │ │ ├── PrepareSendView.kt │ │ │ │ ├── PrepareSendViewModel.kt │ │ │ │ ├── bolt11 │ │ │ │ └── SendToBolt11.kt │ │ │ │ ├── cpfp │ │ │ │ ├── CpfpView.kt │ │ │ │ └── CpfpViewModel.kt │ │ │ │ ├── liquidity │ │ │ │ ├── RequestLiquidityView.kt │ │ │ │ └── RequestLiquidityViewModel.kt │ │ │ │ ├── lnurl │ │ │ │ ├── LnurlAuthView.kt │ │ │ │ ├── LnurlAuthViewModel.kt │ │ │ │ ├── LnurlPayView.kt │ │ │ │ ├── LnurlPayViewModel.kt │ │ │ │ ├── LnurlWithdrawView.kt │ │ │ │ └── LnurlWithdrawViewModel.kt │ │ │ │ ├── offer │ │ │ │ ├── SendOfferView.kt │ │ │ │ └── SendOfferViewModel.kt │ │ │ │ └── spliceout │ │ │ │ ├── SpliceOutView.kt │ │ │ │ └── SpliceOutViewModel.kt │ │ │ ├── security │ │ │ ├── EncryptedData.kt │ │ │ ├── EncryptedPin.kt │ │ │ ├── EncryptedSeed.kt │ │ │ ├── EncryptedSpendingPin.kt │ │ │ ├── KeystoreHelper.kt │ │ │ └── SeedManager.kt │ │ │ ├── services │ │ │ ├── BootReceiver.kt │ │ │ ├── ChannelsWatcher.kt │ │ │ ├── ContactsPhotoCleaner.kt │ │ │ ├── DailyConnect.kt │ │ │ ├── FCMService.kt │ │ │ ├── HceService.kt │ │ │ ├── InflightPaymentsWatcher.kt │ │ │ ├── NodeService.kt │ │ │ ├── NodeState.kt │ │ │ └── WorkerHelper.kt │ │ │ ├── settings │ │ │ ├── AboutView.kt │ │ │ ├── AppAccessSettings.kt │ │ │ ├── ContactsView.kt │ │ │ ├── DisplayPrefsView.kt │ │ │ ├── ExperimentalView.kt │ │ │ ├── ForceCloseView.kt │ │ │ ├── LogsView.kt │ │ │ ├── MutualCloseView.kt │ │ │ ├── NotificationsView.kt │ │ │ ├── PaymentSettingsView.kt │ │ │ ├── ResetWallet.kt │ │ │ ├── SettingsView.kt │ │ │ ├── TorConfigView.kt │ │ │ ├── channels │ │ │ │ ├── ChannelDetailsView.kt │ │ │ │ ├── ChannelsView.kt │ │ │ │ ├── ImportChannelsData.kt │ │ │ │ ├── ImportChannelsDataViewModel.kt │ │ │ │ ├── SpendFromChannelAddress.kt │ │ │ │ └── SpendFromChannelAddressViewModel.kt │ │ │ ├── displayseed │ │ │ │ ├── DisplaySeedView.kt │ │ │ │ └── DisplaySeedViewModel.kt │ │ │ ├── electrum │ │ │ │ ├── ElectrumDialogViewModel.kt │ │ │ │ └── ElectrumView.kt │ │ │ ├── fees │ │ │ │ ├── AdvancedIncomingFeePolicy.kt │ │ │ │ └── LiquidityPolicyView.kt │ │ │ └── walletinfo │ │ │ │ ├── FinalWalletInfo.kt │ │ │ │ ├── FinalWalletRefundView.kt │ │ │ │ ├── FinalWalletRefundViewModel.kt │ │ │ │ ├── SwapInAddresses.kt │ │ │ │ ├── SwapInAddressesViewModel.kt │ │ │ │ ├── SwapInRefundView.kt │ │ │ │ ├── SwapInRefundViewModel.kt │ │ │ │ ├── SwapInSignerView.kt │ │ │ │ ├── SwapInSignerViewModel.kt │ │ │ │ ├── SwapInWalletInfo.kt │ │ │ │ └── WalletInfoView.kt │ │ │ ├── startup │ │ │ ├── StartupView.kt │ │ │ └── StartupViewModel.kt │ │ │ └── utils │ │ │ ├── AnnotatedText.kt │ │ │ ├── BiometricsHelper.kt │ │ │ ├── Clipboard.kt │ │ │ ├── Converter.kt │ │ │ ├── FCMHelper.kt │ │ │ ├── LegacyMigrationHelper.kt │ │ │ ├── Logging.kt │ │ │ ├── SystemNotificationHelper.kt │ │ │ ├── Theme.kt │ │ │ ├── datastore │ │ │ ├── InternalDataRepository.kt │ │ │ └── UserPrefsRepository.kt │ │ │ ├── extensions │ │ │ ├── AndroidContextExtensions.kt │ │ │ ├── CurrencyExtensions.kt │ │ │ ├── ErrorExtensions.kt │ │ │ ├── PaymentExtensions.kt │ │ │ └── TechnicalExtensions.kt │ │ │ ├── images │ │ │ ├── ImageDecoder.kt │ │ │ ├── QRCodeAnalyser.kt │ │ │ └── QRCodeHelper.kt │ │ │ └── nfc │ │ │ ├── ApduCommands.kt │ │ │ ├── NfcHelper.kt │ │ │ ├── NfcParser.kt │ │ │ └── NfcReaderCallback.kt │ └── res │ │ ├── drawable │ │ ├── bucket_noto.png │ │ ├── ic_alert_triangle.xml │ │ ├── ic_arobase.xml │ │ ├── ic_arrow_back.xml │ │ ├── ic_arrow_down_circle.xml │ │ ├── ic_arrow_next.xml │ │ ├── ic_battery_charging.xml │ │ ├── ic_bitcoin.xml │ │ ├── ic_bitcoin_wire.xml │ │ ├── ic_blank.xml │ │ ├── ic_box.xml │ │ ├── ic_brush.xml │ │ ├── ic_bucket.xml │ │ ├── ic_build.xml │ │ ├── ic_calendar.xml │ │ ├── ic_camera.xml │ │ ├── ic_chain.xml │ │ ├── ic_check.xml │ │ ├── ic_check_circle.xml │ │ ├── ic_chevron_down.xml │ │ ├── ic_chevron_right.xml │ │ ├── ic_chevron_up.xml │ │ ├── ic_clipboard.xml │ │ ├── ic_clock.xml │ │ ├── ic_cloud_off.xml │ │ ├── ic_connection_lost.xml │ │ ├── ic_contact_placeholder.xml │ │ ├── ic_copy.xml │ │ ├── ic_cross.xml │ │ ├── ic_cross_circle.xml │ │ ├── ic_curly_braces.xml │ │ ├── ic_delete.xml │ │ ├── ic_dices.xml │ │ ├── ic_edit.xml │ │ ├── ic_exclamation.xml │ │ ├── ic_experimental.xml │ │ ├── ic_external_link.xml │ │ ├── ic_eye.xml │ │ ├── ic_fingerprint.xml │ │ ├── ic_fire.xml │ │ ├── ic_help.xml │ │ ├── ic_help_circle.xml │ │ ├── ic_history.xml │ │ ├── ic_idea.xml │ │ ├── ic_image.xml │ │ ├── ic_info.xml │ │ ├── ic_input.xml │ │ ├── ic_inspect.xml │ │ ├── ic_key.xml │ │ ├── ic_keyboard.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_list.xml │ │ ├── ic_lock.xml │ │ ├── ic_menu_dots.xml │ │ ├── ic_merge.xml │ │ ├── ic_message_circle.xml │ │ ├── ic_minus_circle.xml │ │ ├── ic_nfc.xml │ │ ├── ic_notification.xml │ │ ├── ic_party_popper.xml │ │ ├── ic_paste.xml │ │ ├── ic_payment_details_failure_static.xml │ │ ├── ic_payment_details_pending_onchain_static.xml │ │ ├── ic_payment_details_pending_static.xml │ │ ├── ic_payment_details_success_animated.xml │ │ ├── ic_payment_details_success_static.xml │ │ ├── ic_payment_failed.xml │ │ ├── ic_payment_pending.xml │ │ ├── ic_payment_pending_onchain.xml │ │ ├── ic_payment_success.xml │ │ ├── ic_payment_success_onchain.xml │ │ ├── ic_phoenix.xml │ │ ├── ic_phoenix_outline.xml │ │ ├── ic_pin.xml │ │ ├── ic_plus.xml │ │ ├── ic_plus_circle.xml │ │ ├── ic_qrcode.xml │ │ ├── ic_receive.xml │ │ ├── ic_restore.xml │ │ ├── ic_revert.xml │ │ ├── ic_rocket.xml │ │ ├── ic_sad.xml │ │ ├── ic_scan.xml │ │ ├── ic_scan_qr.xml │ │ ├── ic_send.xml │ │ ├── ic_server.xml │ │ ├── ic_settings.xml │ │ ├── ic_share.xml │ │ ├── ic_shield.xml │ │ ├── ic_sleep.xml │ │ ├── ic_stars.xml │ │ ├── ic_swap.xml │ │ ├── ic_tap.xml │ │ ├── ic_text.xml │ │ ├── ic_tool.xml │ │ ├── ic_tor_shield.xml │ │ ├── ic_tor_shield_ok.xml │ │ ├── ic_trash.xml │ │ ├── ic_trust_badge.xml │ │ ├── ic_unlock.xml │ │ ├── ic_user.xml │ │ ├── ic_user_search.xml │ │ ├── ic_white.xml │ │ ├── ic_zap.xml │ │ ├── illus_phoenix.xml │ │ ├── illus_send.xml │ │ ├── intro_btc.png │ │ ├── intro_cust.png │ │ ├── intro_ln.png │ │ ├── line_dots.xml │ │ └── payment_splash_curve.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values-b+es+419 │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values-cs │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values-de │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values-es │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values-fr │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values-night │ │ └── themes.xml │ │ ├── values-pt-rBR │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values-sk │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values-sw │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values-vi │ │ ├── important_strings.xml │ │ └── strings.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── important_strings.xml │ │ ├── release_notes.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── apduservice.xml │ │ ├── locales_config.xml │ │ └── provider_paths.xml │ └── test │ ├── kotlin │ └── fr │ │ └── acinq │ │ └── phoenix │ │ └── utils │ │ ├── LnurlAuthTest.kt │ │ └── LnurlPayTest.kt │ └── resources │ ├── legacy-incoming.sql │ ├── legacy-metadata.sql │ └── legacy-outgoing.sql ├── phoenix-ios ├── TRANSLATION.md ├── phoenix-ios-framework │ └── Info.plist ├── phoenix-ios.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcshareddata │ │ └── xcschemes │ │ ├── phoenix-ios-framework.xcscheme │ │ ├── phoenix-ios.xcscheme │ │ └── phoenix-notifySrvExt.xcscheme ├── phoenix-ios │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon-Blue.appiconset │ │ │ ├── Contents.json │ │ │ ├── logo_1024.png │ │ │ ├── logo_120 1.png │ │ │ ├── logo_120.png │ │ │ ├── logo_152.png │ │ │ ├── logo_167.png │ │ │ ├── logo_180.png │ │ │ ├── logo_20.png │ │ │ ├── logo_29.png │ │ │ ├── logo_40 1.png │ │ │ ├── logo_40 2.png │ │ │ ├── logo_40.png │ │ │ ├── logo_58 1.png │ │ │ ├── logo_58.png │ │ │ ├── logo_60.png │ │ │ ├── logo_76.png │ │ │ ├── logo_80 1.png │ │ │ ├── logo_80.png │ │ │ └── logo_87.png │ │ ├── AppIcon-Green.appiconset │ │ │ ├── Contents.json │ │ │ ├── logo_1024.png │ │ │ ├── logo_120 1.png │ │ │ ├── logo_120.png │ │ │ ├── logo_152.png │ │ │ ├── logo_167.png │ │ │ ├── logo_180.png │ │ │ ├── logo_20.png │ │ │ ├── logo_29.png │ │ │ ├── logo_40 1.png │ │ │ ├── logo_40 2.png │ │ │ ├── logo_40.png │ │ │ ├── logo_58 1.png │ │ │ ├── logo_58.png │ │ │ ├── logo_60.png │ │ │ ├── logo_76.png │ │ │ ├── logo_80 1.png │ │ │ ├── logo_80.png │ │ │ └── logo_87.png │ │ ├── Contents.json │ │ ├── bitcoin.imageset │ │ │ ├── Contents.json │ │ │ └── bitcoin.svg │ │ ├── bucket.imageset │ │ │ ├── Contents.json │ │ │ └── emoji_u1faa3.svg │ │ ├── bucket_monochrome.imageset │ │ │ ├── Contents.json │ │ │ └── bucket_monochrome.svg │ │ ├── bucket_monochrome_symbol.symbolset │ │ │ ├── Contents.json │ │ │ └── bucket_monochrome_symbol.svg │ │ ├── email.imageset │ │ │ ├── Contents.json │ │ │ └── email.svg │ │ ├── github.imageset │ │ │ ├── Contents.json │ │ │ └── github.svg │ │ ├── ic_arrow_back.imageset │ │ │ ├── Contents.json │ │ │ └── ic_arrow_back.pdf │ │ ├── ic_arrow_next.imageset │ │ │ ├── Contents.json │ │ │ └── ic_arrow_next.pdf │ │ ├── ic_bullet.imageset │ │ │ ├── Contents.json │ │ │ └── ic_bullet.pdf │ │ ├── ic_check.imageset │ │ │ ├── Contents.json │ │ │ └── ic_check.pdf │ │ ├── ic_check_circle.imageset │ │ │ ├── Contents.json │ │ │ └── ic_check_circle.pdf │ │ ├── ic_connection_lost.imageset │ │ │ ├── Contents.json │ │ │ └── ic_connection_lost.pdf │ │ ├── ic_cross.imageset │ │ │ ├── Contents.json │ │ │ └── ic_cross.pdf │ │ ├── ic_edit.imageset │ │ │ ├── Contents.json │ │ │ └── ic_edit.pdf │ │ ├── ic_fire.imageset │ │ │ ├── Contents.json │ │ │ └── ic_fire.pdf │ │ ├── ic_payment_sending.imageset │ │ │ ├── Contents.json │ │ │ └── ic_payment_sending.svg │ │ ├── ic_payment_sent.imageset │ │ │ ├── Contents.json │ │ │ └── ic_payment_sent.svg │ │ ├── ic_payment_success_static.imageset │ │ │ ├── Contents.json │ │ │ └── ic_payment_success_static.pdf │ │ ├── ic_receive.imageset │ │ │ ├── Contents.json │ │ │ └── ic_receive.pdf │ │ ├── ic_receive_resized.imageset │ │ │ ├── Contents.json │ │ │ └── ic_receive_resized.pdf │ │ ├── ic_restore.imageset │ │ │ ├── Contents.json │ │ │ └── ic_restore.pdf │ │ ├── ic_scan.imageset │ │ │ ├── Contents.json │ │ │ └── ic_scan.pdf │ │ ├── ic_scan_resized.imageset │ │ │ ├── Contents.json │ │ │ └── ic_scan_resized.pdf │ │ ├── ic_send.imageset │ │ │ ├── Contents.json │ │ │ └── ic_send.pdf │ │ ├── ic_settings.imageset │ │ │ ├── Contents.json │ │ │ └── ic_settings.pdf │ │ ├── intro_btc.imageset │ │ │ ├── Contents.json │ │ │ └── intro_btc.png │ │ ├── intro_cust.imageset │ │ │ ├── Contents.json │ │ │ └── intro_cust.png │ │ ├── intro_ln.imageset │ │ │ ├── Contents.json │ │ │ └── intro_ln.png │ │ ├── logo_blue.imageset │ │ │ ├── Contents.json │ │ │ └── logo.svg │ │ ├── logo_blue_launch.imageset │ │ │ ├── Contents.json │ │ │ ├── logo_192.png │ │ │ └── logo_384.png │ │ ├── logo_green.imageset │ │ │ ├── Contents.json │ │ │ └── logo.svg │ │ ├── logo_green_launch.imageset │ │ │ ├── Contents.json │ │ │ ├── logo_192.png │ │ │ └── logo_384.png │ │ ├── telegram.imageset │ │ │ ├── Contents.json │ │ │ └── telegram.svg │ │ ├── testnet_bg.imageset │ │ │ ├── Contents.json │ │ │ ├── testnet_dark.png │ │ │ ├── testnet_dark@2x.png │ │ │ ├── testnet_dark@3x.png │ │ │ ├── testnet_light.png │ │ │ ├── testnet_light@2x.png │ │ │ └── testnet_light@3x.png │ │ ├── testnet_bg_svg.imageset │ │ │ ├── Contents.json │ │ │ ├── testnet_dark_path.svg │ │ │ └── testnet_light_path.svg │ │ └── twitter.imageset │ │ │ ├── Contents.json │ │ │ └── twitter.svg │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Colors.xcassets │ │ ├── Contents.json │ │ ├── appAccentBlue.colorset │ │ │ └── Contents.json │ │ ├── appAccentGreen.colorset │ │ │ └── Contents.json │ │ ├── appAccentOrange.colorset │ │ │ └── Contents.json │ │ ├── appNegative.colorset │ │ │ └── Contents.json │ │ ├── appWarn.colorset │ │ │ └── Contents.json │ │ ├── borderColor.colorset │ │ │ └── Contents.json │ │ ├── buttonFill.colorset │ │ │ └── Contents.json │ │ ├── mutedBackground.colorset │ │ │ └── Contents.json │ │ ├── primaryBackground.colorset │ │ │ └── Contents.json │ │ ├── primaryForeground.colorset │ │ │ └── Contents.json │ │ └── textFieldBorder.colorset │ │ │ └── Contents.json │ ├── Currencies.xcstrings │ ├── GoogleService-Info.plist │ ├── Info.plist │ ├── InfoPlist.xcstrings │ ├── Localizable.xcstrings │ ├── MVI │ │ ├── MVI+Extensions.swift │ │ ├── MVI+Mock.swift │ │ └── MVI.swift │ ├── Phoenix.entitlements │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── PrivacyInfo.xcprivacy │ ├── SceneDelegate.swift │ ├── extensions │ │ ├── Bundle+Icon.swift │ │ ├── Collections+AsInt.swift │ │ ├── Data+Hexadecimal.swift │ │ ├── Date+Format.swift │ │ ├── Dictionary+MapKeys.swift │ │ ├── FileHandle+Async.swift │ │ ├── Int+TimeInterval.swift │ │ ├── Int+ToDate.swift │ │ ├── NSItemProvider+Async.swift │ │ ├── NavigationPath+RemoveAll.swift │ │ ├── Result+Deugly.swift │ │ ├── Sequence+Sum.swift │ │ ├── String+Email.swift │ │ ├── String+PIN.swift │ │ ├── String+Substring.swift │ │ ├── String+VersionComparison.swift │ │ ├── Task+Sleep.swift │ │ ├── TextField+Verbatim.swift │ │ └── UIApplicationState+Phoenix.swift │ ├── kotlin │ │ ├── CustomElectrumServerObserver.swift │ │ ├── KotlinAssociatedObject.swift │ │ ├── KotlinEnums.swift │ │ ├── KotlinExtensions+Bitcoin.swift │ │ ├── KotlinExtensions+CloudKit.swift │ │ ├── KotlinExtensions+Conversion.swift │ │ ├── KotlinExtensions+Currency.swift │ │ ├── KotlinExtensions+Lightning.swift │ │ ├── KotlinExtensions+Manager.swift │ │ ├── KotlinExtensions+Other.swift │ │ ├── KotlinExtensions+Payments.swift │ │ ├── KotlinFlow.swift │ │ ├── KotlinIdentifiable.swift │ │ ├── KotlinLogger.swift │ │ ├── KotlinPublishers+Lightning.swift │ │ ├── KotlinPublishers+Phoenix.swift │ │ ├── KotlinTypes.swift │ │ └── ObservableConnectionsMonitor.swift │ ├── logging │ │ ├── LoggerFactory+Background.swift │ │ ├── LoggerFactory+Foreground.swift │ │ ├── LoggerFactory.swift │ │ ├── OSLogHandler.swift │ │ └── fileLogging │ │ │ ├── LogFileHandler.swift │ │ │ ├── LogFileInfo.swift │ │ │ ├── LogFileManager.swift │ │ │ └── LogFileParser.swift │ ├── mempool │ │ ├── MempoolMonitor.swift │ │ └── MempoolRecommendedResponse.swift │ ├── nfc │ │ ├── HceWriter.swift │ │ ├── NfcReader.swift │ │ ├── extensions │ │ │ ├── Array+Read.swift │ │ │ └── ByteArrayConversions.swift │ │ └── tools │ │ │ ├── CapabilitiesContainer.swift │ │ │ ├── CommandAPDU.swift │ │ │ └── Ndef.swift │ ├── officers │ │ ├── AppMigration.swift │ │ ├── BusinessManager.swift │ │ ├── NotificationsManager.swift │ │ ├── PhotosManager.swift │ │ ├── WalletReset.swift │ │ └── WatchTower.swift │ ├── prefs │ │ ├── GroupPrefs.swift │ │ ├── Prefs+BackupSeed.swift │ │ ├── Prefs+BackupTransactions.swift │ │ ├── Prefs.swift │ │ ├── UserDefaults+Codable.swift │ │ └── UserDefaults+Serialization.swift │ ├── security │ │ ├── AppSecurity.swift │ │ ├── EnabledSecurity.swift │ │ ├── GenericPasswordConvertible.swift │ │ ├── GenericPasswordStore.swift │ │ ├── InvalidPin.swift │ │ ├── KeyStoreError.swift │ │ ├── KeychainConstants.swift │ │ ├── RecoveryPhrase.swift │ │ ├── SecurityFile.swift │ │ ├── SharedSecurity.swift │ │ └── TLSConnectionCheck.swift │ ├── sync │ │ ├── SyncBackupManager+Contacts.swift │ │ ├── SyncBackupManager+Payments.swift │ │ ├── SyncBackupManager.swift │ │ ├── SyncBackupManager_Actor.swift │ │ ├── SyncBackupManager_PendingSettings.swift │ │ ├── SyncBackupManager_State.swift │ │ ├── SyncManager.swift │ │ ├── SyncSeedManager.swift │ │ ├── SyncSeedManager_Actor.swift │ │ └── SyncSeedManager_State.swift │ ├── utils │ │ ├── AES256.swift │ │ ├── AnimationCompletion.swift │ │ ├── AppColors.swift │ │ ├── Asserts.swift │ │ ├── Cache.swift │ │ ├── Currency+CurrencyPrefs.swift │ │ ├── Currency.swift │ │ ├── CurrencyAmount.swift │ │ ├── CurrencyPrefs.swift │ │ ├── DelayedSave.swift │ │ ├── Either.swift │ │ ├── FormattedAmount.swift │ │ ├── NestedObservableObject.swift │ │ ├── Orientation.swift │ │ ├── UnfairLock.swift │ │ ├── Utils+CurrencyPrefs.swift │ │ ├── Utils.swift │ │ ├── ViewName.swift │ │ ├── WalletIdentifier.swift │ │ ├── publishers.swift │ │ ├── shapes.swift │ │ └── ui.swift │ ├── views │ │ ├── compatibility │ │ │ ├── GeometryGroup_17.swift │ │ │ ├── ListBackgroundColor.swift │ │ │ ├── NavigationLink_16.swift │ │ │ ├── NavigationStackDestination.swift │ │ │ ├── ScrollView_18.swift │ │ │ └── VibrationFeedback.swift │ │ ├── configuration │ │ │ ├── ConfigurationView.swift │ │ │ ├── advanced │ │ │ │ ├── Experimental.swift │ │ │ │ ├── channels │ │ │ │ │ ├── ChannelInfoPopup.swift │ │ │ │ │ ├── ChannelsConfigurationView.swift │ │ │ │ │ └── ImportChannelsView.swift │ │ │ │ ├── logs │ │ │ │ │ └── LogsConfigurationView.swift │ │ │ │ └── wallet │ │ │ │ │ ├── FinalWalletDetails.swift │ │ │ │ │ ├── SpendOnChainFunds.swift │ │ │ │ │ ├── SwapInAddresses.swift │ │ │ │ │ ├── SwapInWalletDetails.swift │ │ │ │ │ ├── UtxoWrapper.swift │ │ │ │ │ └── WalletInfoView.swift │ │ │ ├── danger zone │ │ │ │ ├── ForceCloseChannelsView.swift │ │ │ │ ├── drain wallet │ │ │ │ │ ├── BtcAddressInput.swift │ │ │ │ │ ├── DrainWalletView.swift │ │ │ │ │ ├── DrainWalletView_Action.swift │ │ │ │ │ ├── DrainWalletView_Confirm.swift │ │ │ │ │ └── ScanBitcoinAddressSheet.swift │ │ │ │ └── reset wallet │ │ │ │ │ ├── ResetWalletView.swift │ │ │ │ │ ├── ResetWalletView_Action.swift │ │ │ │ │ └── ResetWalletView_Confirm.swift │ │ │ ├── fees │ │ │ │ ├── channel management │ │ │ │ │ ├── LiquidityPolicyHelp.swift │ │ │ │ │ └── LiquidityPolicyView.swift │ │ │ │ └── liquidity management │ │ │ │ │ ├── LiquidityAdsHelp.swift │ │ │ │ │ ├── LiquidityAdsView.swift │ │ │ │ │ └── LiquidityFeeInfo.swift │ │ │ ├── general │ │ │ │ ├── AboutView.swift │ │ │ │ ├── WalletCreationOptions.swift │ │ │ │ ├── display configuration │ │ │ │ │ ├── BitcoinUnitSelector.swift │ │ │ │ │ ├── DisplayConfigurationView.swift │ │ │ │ │ ├── FiatCurrencySelector.swift │ │ │ │ │ ├── RecentPaymentsConfig.swift │ │ │ │ │ └── RecentPaymentsSelector.swift │ │ │ │ └── payment options │ │ │ │ │ ├── BackgroundPaymentsConfig.swift │ │ │ │ │ ├── BackgroundPaymentsSelector.swift │ │ │ │ │ └── PaymentOptionsView.swift │ │ │ └── privacy and security │ │ │ │ ├── PaymentsBackupView.swift │ │ │ │ ├── app access │ │ │ │ ├── AppAccessView.swift │ │ │ │ ├── DisablePinView.swift │ │ │ │ ├── EditPinView.swift │ │ │ │ ├── NumberPadView.swift │ │ │ │ ├── SetNewPinView.swift │ │ │ │ └── WhichPinSheet.swift │ │ │ │ ├── electrum server │ │ │ │ ├── ElectrumAddressSheet.swift │ │ │ │ └── ElectrumConfigurationView.swift │ │ │ │ ├── recovery phrase │ │ │ │ ├── AuthenticateWithPinSheet.swift │ │ │ │ ├── CloudBackupView.swift │ │ │ │ └── RecoveryPhraseView.swift │ │ │ │ └── tor │ │ │ │ ├── DisablingTorSheet.swift │ │ │ │ ├── RestartPopover.swift │ │ │ │ ├── TorConfigurationView.swift │ │ │ │ └── UsingTorSheet.swift │ │ ├── contacts │ │ │ ├── AddContactOptionsSheet.swift │ │ │ ├── AddToContactsInfo.swift │ │ │ ├── ContactPhoto.swift │ │ │ ├── ContactsList.swift │ │ │ ├── ContactsListSheet.swift │ │ │ └── ManageContact.swift │ │ ├── content │ │ │ ├── ContentView.swift │ │ │ ├── LoadingView.swift │ │ │ ├── LockState.swift │ │ │ ├── LockView.swift │ │ │ └── RootView.swift │ │ ├── currency_converter │ │ │ ├── CurrencyConverterRow.swift │ │ │ ├── CurrencyConverterView.swift │ │ │ └── CurrencySelector.swift │ │ ├── environment │ │ │ ├── DeepLink.swift │ │ │ ├── DeviceInfo.swift │ │ │ └── GlobalEnvironment.swift │ │ ├── html │ │ │ ├── AboutHTML.swift │ │ │ ├── AnyHTML.swift │ │ │ ├── Base.lproj │ │ │ │ ├── about.html │ │ │ │ └── liquidity.html │ │ │ ├── LiquidityHTML.swift │ │ │ ├── ar.lproj │ │ │ │ └── about.html │ │ │ ├── common.css │ │ │ ├── cs.lproj │ │ │ │ ├── about.html │ │ │ │ └── liquidity.html │ │ │ ├── de.lproj │ │ │ │ ├── about.html │ │ │ │ └── liquidity.html │ │ │ ├── es.lproj │ │ │ │ └── about.html │ │ │ └── fr.lproj │ │ │ │ ├── about.html │ │ │ │ └── liquidity.html │ │ ├── inspect │ │ │ ├── CpfpView.swift │ │ │ ├── Details │ │ │ │ ├── DetailsInfoGrid+CommonSections.swift │ │ │ │ ├── DetailsInfoGrid+CommonValues.swift │ │ │ │ ├── DetailsInfoGrid+ViewHelpers.swift │ │ │ │ ├── DetailsInfoGrid.swift │ │ │ │ ├── DetailsRowWrapper.swift │ │ │ │ ├── DetailsView.swift │ │ │ │ ├── Details_Incoming_Bolt11.swift │ │ │ │ ├── Details_Incoming_Bolt12.swift │ │ │ │ ├── Details_Incoming_LegacyPayToOpen.swift │ │ │ │ ├── Details_Incoming_LegacySwapIn.swift │ │ │ │ ├── Details_Incoming_NewChannel.swift │ │ │ │ ├── Details_Incoming_SpliceIn.swift │ │ │ │ ├── Details_Outgoing_ChannelClose.swift │ │ │ │ ├── Details_Outgoing_Lightning.swift │ │ │ │ ├── Details_Outgoing_LiquidityAuto.swift │ │ │ │ ├── Details_Outgoing_LiquidityManual.swift │ │ │ │ ├── Details_Outgoing_Splice.swift │ │ │ │ ├── Details_Outgoing_SpliceCpfp.swift │ │ │ │ ├── DisplayAmounts.swift │ │ │ │ └── InlineSection.swift │ │ │ ├── EditInfoView.swift │ │ │ ├── PaymentView.swift │ │ │ ├── SummaryInfoGrid.swift │ │ │ ├── SummaryView.swift │ │ │ └── WalletPaymentExtensions.swift │ │ ├── layers │ │ │ ├── Popover.swift │ │ │ ├── ShortSheet.swift │ │ │ ├── SmartModal.swift │ │ │ └── Toast.swift │ │ ├── main │ │ │ ├── AppStatusButton.swift │ │ │ ├── BgRefreshDisabledPopover.swift │ │ │ ├── HomeView.swift │ │ │ ├── IncomingBalancePopover.swift │ │ │ ├── MainView.swift │ │ │ ├── MainView_Big.swift │ │ │ ├── MainView_BigPrimary.swift │ │ │ ├── MainView_Small.swift │ │ │ ├── NavigationCoordinator.swift │ │ │ └── ToolsButton.swift │ │ ├── notifications │ │ │ ├── BizNotificationCell.swift │ │ │ ├── NoticeBox.swift │ │ │ ├── NoticeMonitor.swift │ │ │ ├── NotificationCell.swift │ │ │ ├── NotificationsView.swift │ │ │ └── ServerMessageMonitor.swift │ │ ├── onboarding │ │ │ ├── InitializationView.swift │ │ │ ├── IntroContainer.swift │ │ │ ├── IntroView.swift │ │ │ ├── ManualRestoreView.swift │ │ │ └── RestoreView.swift │ │ ├── receive │ │ │ ├── Bolt12Sheet.swift │ │ │ ├── BtcAddrOptionsSheet.swift │ │ │ ├── CopyShareOptionsSheet.swift │ │ │ ├── InboundFeeSheet.swift │ │ │ ├── InboundFeeState.swift │ │ │ ├── InboundFeeWarning.swift │ │ │ ├── LightningDualView.swift │ │ │ ├── ModifyInvoiceSheet.swift │ │ │ ├── ReceiveView.swift │ │ │ ├── SourceInfo.swift │ │ │ └── SwapInView.swift │ │ ├── send │ │ │ ├── ChannelFundingProblem.swift │ │ │ ├── ChannelSizeImpactWarning.swift │ │ │ ├── CommentSheet.swift │ │ │ ├── FetchActivityNotice.swift │ │ │ ├── LnurlFlowErrorNotice.swift │ │ │ ├── LoginView.swift │ │ │ ├── LowMinerFeeWarning.swift │ │ │ ├── MetadataSheet.swift │ │ │ ├── MinerFeeInfo.swift │ │ │ ├── MinerFeeSheet.swift │ │ │ ├── MsatRange.swift │ │ │ ├── ParseResultHelper.swift │ │ │ ├── PayOfferProblem.swift │ │ │ ├── PaymentDetails.swift │ │ │ ├── PaymentLayerChoice.swift │ │ │ ├── PaymentRequestedView.swift │ │ │ ├── PaymentSummary.swift │ │ │ ├── PaymentWarningPopover.swift │ │ │ ├── PriorityBoxStyle.swift │ │ │ ├── ScanQrCodeView.swift │ │ │ ├── SendView.swift │ │ │ ├── TipSliderSheet.swift │ │ │ ├── ValidateView.swift │ │ │ └── WebsiteLinkPopover.swift │ │ ├── style │ │ │ ├── CenterTopLineAlignment.swift │ │ │ ├── CheckboxToggleStyle.swift │ │ │ ├── EqualSizes.swift │ │ │ ├── InsetGroupBoxStyle.swift │ │ │ ├── LabelAlignment.swift │ │ │ ├── NavigationLinkStyle.swift │ │ │ ├── ScaledButtonStyle.swift │ │ │ ├── ShakeEffect.swift │ │ │ ├── SquareSize.swift │ │ │ ├── TextFieldCurrencyStyler.swift │ │ │ ├── TextFieldNumberStyler.swift │ │ │ ├── Text_CurrencyName.swift │ │ │ ├── ToggleAlignment.swift │ │ │ └── TruncatableView.swift │ │ ├── tools │ │ │ ├── AppStatusPopover.swift │ │ │ ├── MergeChannelsView.swift │ │ │ └── UnlockErrorView.swift │ │ ├── transactions │ │ │ ├── PaymentCell.swift │ │ │ ├── PaymentsSection.swift │ │ │ ├── TransactionsView.swift │ │ │ └── TxHistoryExporter.swift │ │ ├── updates │ │ │ └── V85Popover.swift │ │ └── widgets │ │ │ ├── AnimatedChevron.swift │ │ │ ├── AnimatedClock.swift │ │ │ ├── AnimatedMenu.swift │ │ │ ├── CameraPicker.swift │ │ │ ├── HorizontalActivity.swift │ │ │ ├── ImagePicker.swift │ │ │ ├── InfoGrid.swift │ │ │ ├── InfoPopoverWindow.swift │ │ │ ├── LocalWebView.swift │ │ │ ├── PickerResult.swift │ │ │ ├── QRCode.swift │ │ │ ├── QRCodeScanner.swift │ │ │ ├── TopTab.swift │ │ │ ├── VSlider.swift │ │ │ └── View+If.swift │ └── xpc │ │ ├── XPC+Background.swift │ │ ├── XPC+Foreground.swift │ │ └── XPC.swift ├── phoenix-iosTests │ ├── Info.plist │ ├── aes256Tests.swift │ └── currencyFormattingTests.swift ├── phoenix-iosUITests │ ├── Info.plist │ └── phoenix-iosUITests.swift └── phoenix-notifySrvExt │ ├── Info.plist │ ├── NotificationService.swift │ ├── PhoenixManager.swift │ ├── phoenix-notifySrvExt.entitlements │ └── readme.md ├── phoenix-shared ├── build.gradle.kts └── src │ ├── androidMain │ ├── AndroidManifest.xml │ └── kotlin │ │ └── fr │ │ └── acinq │ │ └── phoenix │ │ ├── data │ │ └── androidElectrumRegtestConf.kt │ │ ├── db │ │ ├── SqlPaymentHooks.kt │ │ └── androidDbFactory.kt │ │ ├── managers │ │ └── NetworkMonitorAndroid.kt │ │ └── utils │ │ ├── logger │ │ └── PhoenixLogWriters.kt │ │ └── platformAndroid.kt │ ├── androidUnitTest │ └── kotlin │ │ └── fr │ │ └── acinq │ │ └── phoenix │ │ ├── data │ │ └── ElectrumServersTest.kt │ │ └── db │ │ ├── SqliteChannelsDatabaseTest.kt │ │ └── SqlitePaymentsDbTest.android.kt │ ├── commonMain │ ├── kotlin │ │ └── fr.acinq.phoenix │ │ │ ├── PhoenixBusiness.kt │ │ │ ├── controllers │ │ │ ├── AppController.kt │ │ │ ├── ControllerFactory.kt │ │ │ ├── MVI.kt │ │ │ ├── config │ │ │ │ ├── CloseChannelsConfiguration.kt │ │ │ │ ├── CloseChannelsConfigurationController.kt │ │ │ │ ├── Configuration.kt │ │ │ │ ├── ConfigurationController.kt │ │ │ │ ├── ElectrumConfiguration.kt │ │ │ │ └── ElectrumConfigurationController.kt │ │ │ ├── init │ │ │ │ ├── InitController.kt │ │ │ │ ├── Initialization.kt │ │ │ │ ├── RestoreWallet.kt │ │ │ │ └── RestoreWalletController.kt │ │ │ ├── main │ │ │ │ ├── Content.kt │ │ │ │ ├── ContentController.kt │ │ │ │ ├── Home.kt │ │ │ │ └── HomeController.kt │ │ │ └── payments │ │ │ │ ├── Receive.kt │ │ │ │ └── ReceiveController.kt │ │ │ ├── csv │ │ │ ├── CsvWriter.kt │ │ │ └── WalletPaymentCsvWriter.kt │ │ │ ├── data │ │ │ ├── AppConfiguration.kt │ │ │ ├── BitcoinAddress.kt │ │ │ ├── ContactInfo.kt │ │ │ ├── DefaultOffer.kt │ │ │ ├── ElectrumServers.kt │ │ │ ├── ExchangeRates.kt │ │ │ ├── LocalChannelInfo.kt │ │ │ ├── MempoolFeerate.kt │ │ │ ├── Notification.kt │ │ │ ├── Wallet.kt │ │ │ ├── WalletContext.kt │ │ │ ├── WalletNotice.kt │ │ │ ├── WalletPayment.kt │ │ │ └── lnurl │ │ │ │ ├── Lnurl.kt │ │ │ │ ├── LnurlAuth.kt │ │ │ │ ├── LnurlError.kt │ │ │ │ ├── LnurlPay.kt │ │ │ │ └── LnurlWithdraw.kt │ │ │ ├── db │ │ │ ├── DbFactory.kt │ │ │ ├── DbHooks.kt │ │ │ ├── DbInitHelper.kt │ │ │ ├── SqliteAppDb.kt │ │ │ ├── SqliteChannelsDb.kt │ │ │ ├── SqlitePaymentsDb.kt │ │ │ ├── cloud │ │ │ │ ├── CloudHelper.kt │ │ │ │ ├── CloudSerializers.kt │ │ │ │ ├── contacts │ │ │ │ │ └── CloudContact.kt │ │ │ │ └── payments │ │ │ │ │ ├── ChannelCloseType.kt │ │ │ │ │ ├── CloudAsset.kt │ │ │ │ │ ├── CloudData.kt │ │ │ │ │ ├── InboundLiquidityPaymentWrapper.kt │ │ │ │ │ ├── IncomingPaymentWrapperV10Legacy.kt │ │ │ │ │ ├── LightningOutgoingPartType.kt │ │ │ │ │ ├── LightningOutgoingType.kt │ │ │ │ │ ├── SpliceCpfpPaymentType.kt │ │ │ │ │ └── SpliceOutgoingType.kt │ │ │ ├── contacts │ │ │ │ ├── ContactQueries.kt │ │ │ │ └── SqliteContactsDb.kt │ │ │ ├── migrations │ │ │ │ ├── appDb │ │ │ │ │ └── v7 │ │ │ │ │ │ └── AfterVersion7.kt │ │ │ │ ├── v10 │ │ │ │ │ ├── AfterVersion10.kt │ │ │ │ │ ├── json │ │ │ │ │ │ ├── AbstractStringSerializer.kt │ │ │ │ │ │ ├── ByteVectorSerializer.kt │ │ │ │ │ │ ├── MilliSatoshiSerializer.kt │ │ │ │ │ │ ├── OutpointSerializer.kt │ │ │ │ │ │ ├── SatoshiSerializer.kt │ │ │ │ │ │ ├── TxIdSerializer.kt │ │ │ │ │ │ └── UUIDSerializer.kt │ │ │ │ │ └── types │ │ │ │ │ │ └── IncomingTypes.kt │ │ │ │ └── v11 │ │ │ │ │ ├── AfterVersion11.kt │ │ │ │ │ ├── queries │ │ │ │ │ ├── ChannelCloseOutgoingQueries.kt │ │ │ │ │ ├── InboundLiquidityQueries.kt │ │ │ │ │ ├── LightningOutgoingQueries.kt │ │ │ │ │ ├── SpliceCpfpOutgoingQueries.kt │ │ │ │ │ └── SpliceOutgoingQueries.kt │ │ │ │ │ └── types │ │ │ │ │ ├── OutgoingDetailsType.kt │ │ │ │ │ ├── OutgoingPartClosingType.kt │ │ │ │ │ ├── OutgoingPartStatusType.kt │ │ │ │ │ ├── OutgoingStatusType.kt │ │ │ │ │ └── liquidityads │ │ │ │ │ ├── FundingFeeData.kt │ │ │ │ │ ├── LegacyLeaseData.kt │ │ │ │ │ ├── PaymentDetailsData.kt │ │ │ │ │ └── PurchaseData.kt │ │ │ ├── notifications │ │ │ │ ├── NotificationDataType.kt │ │ │ │ └── NotificationsQueries.kt │ │ │ ├── payments │ │ │ │ ├── CloudKitInterface.kt │ │ │ │ ├── MetadataTypes.kt │ │ │ │ ├── PaymentsMetadataQueries.kt │ │ │ │ ├── SqliteIncomingPaymentsDb.kt │ │ │ │ └── SqliteOutgoingPaymentsDb.kt │ │ │ └── serialization │ │ │ │ └── contacts │ │ │ │ ├── Serialization.kt │ │ │ │ └── v1 │ │ │ │ ├── Deserialization.kt │ │ │ │ └── Serialization.kt │ │ │ ├── managers │ │ │ ├── AppConfigurationManager.kt │ │ │ ├── AppConnectionsDaemon.kt │ │ │ ├── BalanceManager.kt │ │ │ ├── ConnectionsManager.kt │ │ │ ├── CurrencyManager.kt │ │ │ ├── DatabaseManager.kt │ │ │ ├── LnurlManager.kt │ │ │ ├── NetworkMonitor.kt │ │ │ ├── NodeParamsManager.kt │ │ │ ├── NotificationsManager.kt │ │ │ ├── PaymentsManager.kt │ │ │ ├── PaymentsPageFetcher.kt │ │ │ ├── PeerManager.kt │ │ │ ├── SendManager.kt │ │ │ └── WalletManager.kt │ │ │ └── utils │ │ │ ├── BlockchainExplorer.kt │ │ │ ├── Cache.kt │ │ │ ├── DnsResolvers.kt │ │ │ ├── MetadataQueue.kt │ │ │ ├── MnemonicLanguage.kt │ │ │ ├── Parser.kt │ │ │ ├── PlatformContext.kt │ │ │ ├── SwiftFlow.kt │ │ │ ├── channels │ │ │ ├── ChannelsImportHelper.kt │ │ │ └── SpendChannelAddressHelper.kt │ │ │ ├── extensions │ │ │ ├── ChainExtensions.kt │ │ │ ├── ChannelExtensions.kt │ │ │ ├── ConnectionExtensions.kt │ │ │ ├── MiscExtensions.kt │ │ │ ├── PaymentExtensions.kt │ │ │ ├── PaymentRequestExtensions.kt │ │ │ └── WalletStateExtensions.kt │ │ │ ├── logger │ │ │ └── LoggerConfig.kt │ │ │ └── migrations │ │ │ ├── IosMigrationHelper.kt │ │ │ └── LegacyChannelCloseHelper.kt │ └── sqldelight │ │ ├── appdb │ │ └── fr │ │ │ └── acinq │ │ │ └── phoenix │ │ │ └── db │ │ │ └── sqldelight │ │ │ ├── ExchangeRates.sq │ │ │ ├── KeyValueStore.sq │ │ │ ├── Notifications.sq │ │ │ └── migrations │ │ │ ├── 1.sqm │ │ │ ├── 2.sqm │ │ │ ├── 3.sqm │ │ │ ├── 4.sqm │ │ │ ├── 5.sqm │ │ │ ├── 6.sqm │ │ │ └── 7.sqm │ │ ├── channelsdb │ │ └── fr │ │ │ └── acinq │ │ │ └── phoenix │ │ │ └── db │ │ │ └── sqldelight │ │ │ └── ChannelsDatabase.sq │ │ └── paymentsdb │ │ ├── fr │ │ └── acinq │ │ │ └── phoenix │ │ │ └── db │ │ │ └── sqldelight │ │ │ ├── CloudKitContacts.sq │ │ │ ├── CloudKitPayments.sq │ │ │ ├── Contacts.sq │ │ │ ├── OnChainTransactions.sq │ │ │ ├── Payments.sq │ │ │ ├── PaymentsIncoming.sq │ │ │ ├── PaymentsMetadata.sq │ │ │ └── PaymentsOutgoing.sq │ │ └── migrations │ │ ├── 1.sqm │ │ ├── 10.sqm │ │ ├── 11.sqm │ │ ├── 12.sqm │ │ ├── 2.sqm │ │ ├── 3.sqm │ │ ├── 4.sqm │ │ ├── 5.sqm │ │ ├── 6.sqm │ │ ├── 7.sqm │ │ ├── 8.sqm │ │ └── 9.sqm │ ├── commonTest │ ├── kotlin │ │ └── fr │ │ │ └── acinq │ │ │ └── phoenix │ │ │ ├── TestConstants.kt │ │ │ ├── data │ │ │ ├── ElectrumServersTest.kt │ │ │ └── lnurl │ │ │ │ ├── LnurlAuthTest.kt │ │ │ │ ├── LnurlPayTest.kt │ │ │ │ └── LnurlWithdrawTest.kt │ │ │ ├── db │ │ │ ├── SqliteChannelsDbTest.kt │ │ │ ├── SqlitePaymentsDbTest.kt │ │ │ └── cloud │ │ │ │ └── CloudDataTest.kt │ │ │ └── utils │ │ │ ├── CacheTests.kt │ │ │ ├── ConnectionTests.kt │ │ │ ├── CsvWriterTests.kt │ │ │ ├── DnsResolversTests.kt │ │ │ ├── ParserTest.kt │ │ │ └── TestLoggerFactory.kt │ └── resources │ │ └── sampledbs │ │ ├── v1 │ │ ├── payments-testnet-a224978853d2f4c94ac8e2dbb2acf8344e0146d0.sqlite │ │ └── payments-testnet-fedc36138a62ceadc8a93861d2c46f5ca5e8b418.sqlite │ │ ├── v10 │ │ ├── payments-testnet-28903aff.sqlite │ │ ├── payments-testnet-6a5e6f.sqlite │ │ └── payments-testnet-f921bddf.sqlite │ │ └── v6 │ │ └── payments-testnet-700486fc7a90d5922d6f993f2941ab9f9f1a9d85.sqlite │ ├── iosMain │ └── kotlin │ │ └── fr │ │ └── acinq │ │ └── phoenix │ │ ├── data │ │ └── iosElectrumRegtestConf.kt │ │ ├── db │ │ ├── CloudKitContactsDb.kt │ │ ├── CloudKitDb.kt │ │ ├── CloudKitPaymentsDb.kt │ │ ├── SqlPaymentHooks.kt │ │ └── iosDbFactory.kt │ │ ├── managers │ │ └── NetworkMonitorIos.kt │ │ └── utils │ │ ├── LightningExposure.kt │ │ ├── OSLogWriter.kt │ │ ├── PassthruLogWriter.kt │ │ ├── PhoenixExposure.kt │ │ ├── logger │ │ └── PhoenixLogWriters.kt │ │ └── platformIos.kt │ └── iosTest │ └── kotlin │ └── fr │ └── acinq │ └── phoenix │ ├── data │ └── ElectrumServersTest.kt │ └── db │ ├── PaymentsDbMigrationTest.ios.kt │ └── SqliteChannelsDatabaseTest.kt └── settings.gradle.kts /.gitattributes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/.gitattributes -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build 2 | build/ 3 | .kotlin/ 4 | 5 | # Idea 6 | .idea 7 | *.iml 8 | 9 | # Gradle 10 | .gradle 11 | local.properties 12 | .gradletasknamecache 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # XCode 18 | xcuserdata/ 19 | 20 | # Android 21 | phoenix-android/debug/ 22 | phoenix-android/release/ 23 | .externalNativeBuild 24 | sdk-dependencies 25 | apk 26 | .cxx 27 | logs/ 28 | 29 | # LangTool 30 | .langtool/deepl.authtoken 31 | 32 | -------------------------------------------------------------------------------- /.langtool/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "androidResDirectory" : "phoenix-android/src/main/res/", 3 | "deepL" : { 4 | "es" : { 5 | "formality" : "prefer_less" 6 | }, 7 | "es-419" : { 8 | "formality" : "prefer_less", 9 | "target" : "es" 10 | }, 11 | "fr" : { 12 | "formality" : "prefer_more" 13 | } 14 | }, 15 | "iosXcstringsFiles" : [ 16 | "phoenix-ios/phoenix-ios/Localizable.xcstrings" 17 | ] 18 | } -------------------------------------------------------------------------------- /.readme/phoenix_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/.readme/phoenix_text.png -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath(libs.agp) 9 | classpath(libs.kgp) 10 | classpath(libs.serialization) 11 | classpath(libs.sqldelight.plugin) 12 | classpath(libs.fcm.plugin) 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | mavenLocal() 19 | google() 20 | mavenCentral() 21 | maven("https://oss.sonatype.org/content/repositories/snapshots") 22 | } 23 | } 24 | 25 | val clean by tasks.creating(Delete::class) { 26 | delete(rootProject.layout.buildDirectory) 27 | } 28 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2019 ACINQ SAS 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # Gradle 18 | org.gradle.jvmargs = -Xmx2048m 19 | org.gradle.parallel = true 20 | 21 | # Kotlin 22 | kotlin.code.style = official 23 | kotlin.mpp.stability.nowarn = true 24 | kotlin.mpp.enableCInteropCommonization = true 25 | 26 | # Android 27 | android.useAndroidX = true 28 | 29 | # iOS 30 | xcodeproj=phoenix-ios/phoenix-ios.xcodeproj 31 | 32 | # the chain that we use 33 | chain="testnet" 34 | android.nonTransitiveRClass=false 35 | android.nonFinalResIds=false 36 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Feb 26 17:56:48 CET 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip 7 | -------------------------------------------------------------------------------- /local.properties.template: -------------------------------------------------------------------------------- 1 | # This file defines whether Android is loaded by Gradle & IntelliJ. 2 | # At least one of both properties 'sdk.dir' or 'skip.android' must be set. 3 | 4 | # Must be set in order for Android to be loaded. 5 | #sdk.dir=/Location/to/Android/sdk 6 | 7 | # Instructs Gradle to skip Android. 8 | # Note that this property takes precedence over sdk.dir (you can have sdk.dir set and still skip Android). 9 | #skip.android=true 10 | -------------------------------------------------------------------------------- /phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/utils/FCMHelper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.android.utils 18 | 19 | import android.content.Context 20 | import com.google.android.gms.common.ConnectionResult 21 | import com.google.android.gms.common.GoogleApiAvailability 22 | 23 | object FCMHelper { 24 | fun isFCMAvailable(context: Context): Boolean { 25 | return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS 26 | } 27 | } -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/bucket_noto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/drawable/bucket_noto.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_arobase.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_blank.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_check.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_chevron_down.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_chevron_right.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 14 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_chevron_up.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_contact_placeholder.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_curly_braces.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_external_link.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_history.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_idea.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_image.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_inspect.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_menu_dots.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_minus_circle.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_notification.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_payment_pending_onchain.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_payment_success.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_payment_success_onchain.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_plus.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_plus_circle.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 27 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_revert.xml: -------------------------------------------------------------------------------- 1 | 6 | 13 | 20 | 21 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_scan.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_shield.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_white.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/ic_zap.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/intro_btc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/drawable/intro_btc.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/intro_cust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/drawable/intro_cust.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/intro_ln.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/drawable/intro_ln.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/line_dots.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/drawable/payment_splash_curve.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /phoenix-android/src/main/res/values-es/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | #5741D9 20 | #50B338 21 | #1AC486 22 | #91B4D1 23 | #25a5ff 24 | #171B22 25 | #ffffff 26 | #f0f5f7 27 | #000000 28 | 29 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4dp 4 | 32dp 5 | 6 | 18dp 7 | 8 | 9 | 1000dp 10 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/values/release_notes.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Version 2.5.0: Tor changes 19 | Enabling Tor now requires installing a third-party Tor Proxy VPN app such as Orbot.\n\nThis makes background payments much more reliable with Tor.\n\nAlso Phoenix now always uses onion addresses for Lightning and Electrum connections when Tor is enabled.. 20 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/xml/apduservice.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 21 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/xml/locales_config.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /phoenix-android/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /phoenix-ios/TRANSLATION.md: -------------------------------------------------------------------------------- 1 | This document provides guidelines for localizing the iOS application. 2 | 3 | ## How to add a new language 4 | 5 | 1. Fork and clone this project ([How-to](https://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project)) 6 | 2. Create a new branch, for example `translate_mylanguagecode`, where my `mylanguagecode` could be `fr` or `it`. 7 | 3. In XCode, select the root project file and go to the project panel, Info tab. Find the localization section and click the `+` button to add your desired language. Then select all the resource files in the list (including the `.html` files). 8 | 4. A copy of each file has been created for the new language. You can now start the translation work proper. 9 | 10 | ## Guidelines 11 | 12 | #### Dynamic content 13 | 14 | Some content is dynamic: a part of it will contain a dynamic value, such as an amount, that will be injected by the application at runtime. In that case, these strings will contain a special data formatted like this: `%@`, `%s`, `%1$`... This part must not be translated. 15 | 16 | #### Additional guidelines 17 | 18 | See [here](https://github.com/ACINQ/phoenix/blob/master/TRANSLATION.md#general-considerations). -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios-framework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_1024.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_120 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_120 1.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_120.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_152.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_167.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_180.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_20.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_29.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_40 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_40 1.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_40 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_40 2.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_40.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_58 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_58 1.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_58.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_60.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_76.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_80 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_80 1.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_80.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Blue.appiconset/logo_87.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_1024.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_120 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_120 1.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_120.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_152.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_167.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_180.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_20.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_29.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_40 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_40 1.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_40 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_40 2.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_40.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_58 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_58 1.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_58.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_60.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_76.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_80 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_80 1.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_80.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/AppIcon-Green.appiconset/logo_87.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/bitcoin.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "bitcoin.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/bucket.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "emoji_u1faa3.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/bucket_monochrome.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "bucket_monochrome.svg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/bucket_monochrome_symbol.symbolset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "symbols" : [ 7 | { 8 | "filename" : "bucket_monochrome_symbol.svg", 9 | "idiom" : "universal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/email.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "email.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/email.imageset/email.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/github.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "github.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_arrow_back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_arrow_back.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_arrow_back.imageset/ic_arrow_back.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_arrow_back.imageset/ic_arrow_back.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_arrow_next.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_arrow_next.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_arrow_next.imageset/ic_arrow_next.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_arrow_next.imageset/ic_arrow_next.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_bullet.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_bullet.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_bullet.imageset/ic_bullet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_bullet.imageset/ic_bullet.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_check.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_check.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_check.imageset/ic_check.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_check.imageset/ic_check.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_check_circle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_check_circle.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_check_circle.imageset/ic_check_circle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_check_circle.imageset/ic_check_circle.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_connection_lost.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_connection_lost.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_connection_lost.imageset/ic_connection_lost.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_connection_lost.imageset/ic_connection_lost.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_cross.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_cross.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_cross.imageset/ic_cross.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_cross.imageset/ic_cross.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_edit.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_edit.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_edit.imageset/ic_edit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_edit.imageset/ic_edit.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_fire.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_fire.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_fire.imageset/ic_fire.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_fire.imageset/ic_fire.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_payment_sending.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_payment_sending.svg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_payment_sending.imageset/ic_payment_sending.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_payment_sent.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_payment_sent.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "compression-type" : "lossless", 14 | "preserves-vector-representation" : true, 15 | "template-rendering-intent" : "template" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_payment_sent.imageset/ic_payment_sent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_payment_success_static.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_payment_success_static.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_payment_success_static.imageset/ic_payment_success_static.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_payment_success_static.imageset/ic_payment_success_static.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_receive.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_receive.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_receive.imageset/ic_receive.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_receive.imageset/ic_receive.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_receive_resized.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_receive_resized.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_receive_resized.imageset/ic_receive_resized.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_receive_resized.imageset/ic_receive_resized.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_restore.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_restore.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_restore.imageset/ic_restore.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_restore.imageset/ic_restore.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_scan.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_scan.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_scan.imageset/ic_scan.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_scan.imageset/ic_scan.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_scan_resized.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_scan_resized.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_scan_resized.imageset/ic_scan_resized.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_scan_resized.imageset/ic_scan_resized.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_send.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_send.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_send.imageset/ic_send.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_send.imageset/ic_send.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_settings.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ic_settings.pdf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/ic_settings.imageset/ic_settings.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/ic_settings.imageset/ic_settings.pdf -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/intro_btc.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "intro_btc.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/intro_btc.imageset/intro_btc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/intro_btc.imageset/intro_btc.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/intro_cust.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "intro_cust.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/intro_cust.imageset/intro_cust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/intro_cust.imageset/intro_cust.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/intro_ln.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "intro_ln.png", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/intro_ln.imageset/intro_ln.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/intro_ln.imageset/intro_ln.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_blue.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_blue.imageset/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_blue_launch.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo_192.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "logo_384.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_blue_launch.imageset/logo_192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/logo_blue_launch.imageset/logo_192.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_blue_launch.imageset/logo_384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/logo_blue_launch.imageset/logo_384.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_green.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_green.imageset/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_green_launch.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo_192.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "logo_384.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_green_launch.imageset/logo_192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/logo_green_launch.imageset/logo_192.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/logo_green_launch.imageset/logo_384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/logo_green_launch.imageset/logo_384.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/telegram.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "telegram.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/telegram.imageset/telegram.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_dark.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_dark@2x.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_dark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_dark@3x.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_light.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_light@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_light@2x.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_light@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg.imageset/testnet_light@3x.png -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/testnet_bg_svg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "testnet_light_path.svg", 5 | "idiom" : "universal" 6 | }, 7 | { 8 | "appearances" : [ 9 | { 10 | "appearance" : "luminosity", 11 | "value" : "dark" 12 | } 13 | ], 14 | "filename" : "testnet_dark_path.svg", 15 | "idiom" : "universal" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | }, 22 | "properties" : { 23 | "preserves-vector-representation" : true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Assets.xcassets/twitter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "twitter.svg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true, 14 | "template-rendering-intent" : "template" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/appAccentBlue.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xFF", 9 | "green" : "0xA5", 10 | "red" : "0x25" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xFF", 27 | "green" : "0xA5", 28 | "red" : "0x25" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/appAccentGreen.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x38", 9 | "green" : "0xB3", 10 | "red" : "0x50" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x62", 27 | "green" : "0xB9", 28 | "red" : "0x00" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/appAccentOrange.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x25", 9 | "green" : "0xA5", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x25", 27 | "green" : "0xA5", 28 | "red" : "0xFF" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/appNegative.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "79", 9 | "green" : "79", 10 | "red" : "209" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "89", 27 | "green" : "89", 28 | "red" : "219" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/appWarn.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x2E", 9 | "green" : "0xBC", 10 | "red" : "0xFE" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "56", 27 | "green" : "198", 28 | "red" : "255" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/borderColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xED", 9 | "green" : "0xEB", 10 | "red" : "0xE1" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x6C", 27 | "green" : "0x58", 28 | "red" : "0x4E" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/buttonFill.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "0.990", 10 | "red" : "0.990" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "platform" : "ios", 24 | "reference" : "secondarySystemBackgroundColor" 25 | }, 26 | "idiom" : "universal" 27 | } 28 | ], 29 | "info" : { 30 | "author" : "xcode", 31 | "version" : 1 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/mutedBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xFF", 9 | "green" : "0xFF", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x1D", 27 | "green" : "0x19", 28 | "red" : "0x16" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/primaryForeground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x3E", 9 | "green" : "0x31", 10 | "red" : "0x2B" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "platform" : "ios", 24 | "reference" : "labelColor" 25 | }, 26 | "idiom" : "universal" 27 | } 28 | ], 29 | "info" : { 30 | "author" : "xcode", 31 | "version" : 1 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Colors.xcassets/textFieldBorder.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "platform" : "ios", 6 | "reference" : "separatorColor" 7 | }, 8 | "idiom" : "universal" 9 | }, 10 | { 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "color" : { 18 | "platform" : "ios", 19 | "reference" : "systemGray2Color" 20 | }, 21 | "idiom" : "universal" 22 | } 23 | ], 24 | "info" : { 25 | "author" : "xcode", 26 | "version" : 1 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/MVI/MVI+Extensions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | 5 | extension MVIState where Model: CloseChannelsConfiguration.Model, Intent: CloseChannelsConfiguration.Intent { 6 | 7 | func channels() -> [CloseChannelsConfiguration.ModelChannelInfo]? { 8 | 9 | if let model = self.model as? CloseChannelsConfiguration.ModelReady { 10 | return model.channels 11 | } else if let model = self.model as? CloseChannelsConfiguration.ModelChannelsClosed { 12 | return model.channels 13 | } else { 14 | return nil 15 | } 16 | } 17 | 18 | func balanceSats() -> Int64 { 19 | 20 | // Note that there's a subtle difference between 21 | // - global balance => sum of local millisatoshi amount in each open channel 22 | // - closing balance => some of local satoshi amount in each open channel 23 | // 24 | // When closing a channel, the extra millisatoshi amount gets truncated. 25 | // For this reason, there could be a small difference. 26 | 27 | if let channels = channels() { 28 | return channels.map { $0.balance?.sat ?? 0 }.reduce(0, +) 29 | } else { 30 | return 0 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Phoenix.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.icloud-container-identifiers 8 | 9 | iCloud.co.acinq.phoenix 10 | 11 | com.apple.developer.icloud-services 12 | 13 | CloudKit 14 | 15 | com.apple.developer.nfc.hce 16 | 17 | com.apple.developer.nfc.hce.iso7816.select-identifier-prefixes 18 | 19 | D2760000850101 20 | 21 | com.apple.developer.nfc.readersession.formats 22 | 23 | TAG 24 | 25 | com.apple.security.application-groups 26 | 27 | group.co.acinq.phoenix 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryDiskSpace 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | E174.1 13 | 14 | 15 | 16 | NSPrivacyAccessedAPIType 17 | NSPrivacyAccessedAPICategoryUserDefaults 18 | NSPrivacyAccessedAPITypeReasons 19 | 20 | CA92.1 21 | 1C8F.1 22 | 23 | 24 | 25 | NSPrivacyAccessedAPIType 26 | NSPrivacyAccessedAPICategoryFileTimestamp 27 | NSPrivacyAccessedAPITypeReasons 28 | 29 | C617.1 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/Bundle+Icon.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | extension Bundle { 4 | 5 | public var icon: UIImage? { 6 | guard 7 | let icons = infoDictionary?["CFBundleIcons"] as? [String: Any], 8 | let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any], 9 | let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String], 10 | let lastIcon = iconFiles.last 11 | else { 12 | return nil 13 | } 14 | return UIImage(named: lastIcon) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/Collections+AsInt.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Collection where Element: Equatable { 4 | 5 | /// The built-in function `firstIndex(of:)` returns a value of type `Self.Index`. 6 | /// That can be annoying if you were hoping for result as an Int value. 7 | /// This extension function performs that conversion for you. 8 | /// 9 | func firstIndexAsInt(of element: Self.Element) -> Int? { 10 | if let idx = firstIndex(of: element) { 11 | return distance(from: startIndex, to: idx) 12 | } else { 13 | return nil 14 | } 15 | } 16 | } 17 | 18 | extension BidirectionalCollection where Element: Equatable { 19 | 20 | /// The built-in function `lastIndex(of:)` returns a value of type `Self.Index`. 21 | /// That can be annoying if you were hoping for result as an Int value. 22 | /// This extension function performs that conversion for you. 23 | /// 24 | func lastIndexAsInt(of element: Self.Element) -> Int? { 25 | if let idx = lastIndex(of: element) { 26 | return distance(from: startIndex, to: idx) 27 | } else { 28 | return nil 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/Date+Format.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Date { 4 | 5 | /// Note that `Date.formatted()` & `Date.FormatStyle` is iOS 15+. 6 | /// So until we drop support for iOS 14, we won't be using it. 7 | /// 8 | func format( 9 | date dateStyle: DateFormatter.Style = .long, 10 | time timeStyle: DateFormatter.Style = .short 11 | ) -> String { 12 | let formatter = DateFormatter() 13 | formatter.dateStyle = dateStyle 14 | formatter.timeStyle = timeStyle 15 | return formatter.string(from: self) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/FileHandle+Async.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension FileHandle { 4 | 5 | func asyncWrite( 6 | data: any DataProtocol, 7 | qos: DispatchQoS.QoSClass = .userInitiated 8 | ) async throws { 9 | 10 | try self.write(contentsOf: data) 11 | } 12 | 13 | func asyncSyncAndClose( 14 | qos: DispatchQoS.QoSClass = .userInitiated 15 | ) async throws { 16 | 17 | try self.synchronize() 18 | try self.close() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/Int+TimeInterval.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | extension Int { 5 | 6 | func milliseconds() -> TimeInterval { 7 | return Double(self) / Double(1_000) 8 | } 9 | 10 | func seconds() -> TimeInterval { 11 | return Double(self) 12 | } 13 | 14 | func minutes() -> TimeInterval { 15 | return Double(self) * Double(60) 16 | } 17 | 18 | func hours() -> TimeInterval { 19 | return Double(self) * Double(60 * 60) 20 | } 21 | 22 | func days() -> TimeInterval { 23 | return Double(self) * Double(60 * 60 * 24) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/Int+ToDate.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | 5 | enum TimestampType { 6 | case milliseconds 7 | case seconds 8 | } 9 | 10 | extension Int64 { 11 | 12 | func toDate(from timestampType: TimestampType) -> Date { 13 | switch timestampType { 14 | case .milliseconds : return Date(timeIntervalSince1970: TimeInterval(self) / TimeInterval(1_000)) 15 | case .seconds : return Date(timeIntervalSince1970: TimeInterval(self)) 16 | } 17 | } 18 | 19 | func minus(hours: Int) -> Int64 { 20 | return self - Int64(1_000 * 60 * 60 * hours) 21 | } 22 | 23 | func toKotlinLong() -> KotlinLong { 24 | return KotlinLong(longLong: self) 25 | } 26 | } 27 | 28 | extension Date { 29 | 30 | func toMilliseconds() -> Int64 { 31 | return Int64(self.timeIntervalSince1970 * 1_000) 32 | } 33 | 34 | func toMillisecondsKotlinLong() -> KotlinLong { 35 | return self.toMilliseconds().toKotlinLong() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/NavigationPath+RemoveAll.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | extension NavigationPath { 4 | 5 | mutating func removeAll() { 6 | if self.count > 0 { 7 | self.removeLast(self.count) 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/Result+Deugly.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // In earlier versions of Swift, you could setup an enum with Void type: 4 | // ``` 5 | // enum Result { 6 | // case success(T) 7 | // case error(Error?) 8 | // } 9 | // ``` 10 | // 11 | // And then you could omit the associated value of type Void: 12 | // ``` 13 | // finish(.success()) 14 | // ``` 15 | // 16 | // This no longer works as of Swift 4, and now you have to do one of: 17 | // ``` 18 | // finish(.success(())) 19 | // finish(.success(Void())) 20 | // ``` 21 | // 22 | // The community consensus is that this is "ugly". 23 | // And this extension restores the cleanliness of previous Swift versions. 24 | // 25 | extension Result where Success == Void { 26 | static var success: Result { 27 | return .success(()) 28 | } 29 | } 30 | 31 | // These should exist in the standard library, but they don't. 32 | extension Result { 33 | 34 | var isSuccess: Bool { 35 | if case .success = self { 36 | return true 37 | } else { 38 | return false 39 | } 40 | } 41 | 42 | var isError: Bool { 43 | return !isSuccess 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/Sequence+Sum.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Sequence where Element: AdditiveArithmetic { 4 | func sum() -> Element { reduce(.zero, +) } 5 | } 6 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/String+Email.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension String { 4 | 5 | func isValidEmailAddress() -> Bool { 6 | let types: NSTextCheckingResult.CheckingType = [.link] 7 | guard let linkDetector = try? NSDataDetector(types: types.rawValue) else { 8 | return false 9 | } 10 | let range = NSRange(location: 0, length: self.count) 11 | let result = linkDetector.firstMatch(in: self, options: .reportCompletion, range: range) 12 | let scheme = result?.url?.scheme ?? "" 13 | return (scheme == "mailto") && (result?.range.length == self.count) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/String+PIN.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension String { 4 | 5 | var isValidPIN: Bool { 6 | 7 | if self.count != 6 { 8 | return false 9 | } 10 | 11 | let digitsCharacters = CharacterSet(charactersIn: "0123456789") 12 | return CharacterSet(charactersIn: self).isSubset(of: digitsCharacters) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/String+Substring.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension String { 4 | 5 | /// Getting the substring of a String in Swift is complete insanity. 6 | /// This function works like substring in most other languages. 7 | /// 8 | func substring(location: Int, length: Int? = nil) -> String { 9 | let start = min(max(0, location), self.count) 10 | let limitedLength = min(self.count - start, length ?? Int.max) 11 | let from = index(startIndex, offsetBy: start) 12 | let to = index(startIndex, offsetBy: start + limitedLength) 13 | return String(self[from.. String { 17 | return substring(location: 0, length: length) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/Task+Sleep.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Task where Success == Never, Failure == Never { 4 | 5 | static func sleep(seconds: TimeInterval) async throws { 6 | try await Task.sleep(for: Duration.seconds(seconds)) 7 | } 8 | 9 | static func sleep(hours: Int) async throws { 10 | try await sleep(seconds: TimeInterval(hours) * 60 * 60) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/TextField+Verbatim.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | 4 | extension TextField where Label == Text { 5 | 6 | /// Text has a nice initializer we can use when we don't need to localize the string: 7 | /// ``` 8 | /// Text(verbatim: String) 9 | /// ``` 10 | /// 11 | /// TextField is missing this, so we're adding it here. 12 | init( 13 | verbatim: String, 14 | text: Binding, 15 | onEditingChanged: @escaping (Bool) -> Void = { _ in }, 16 | onCommit: @escaping () -> Void = {} 17 | ) { 18 | self.init(verbatim, text: text, onEditingChanged: onEditingChanged, onCommit: onCommit) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/extensions/UIApplicationState+Phoenix.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | 4 | extension UIApplication.State: @retroactive CustomStringConvertible { 5 | 6 | public var description: String { 7 | switch self { 8 | case .inactive : return "inactive" 9 | case .active : return "active" 10 | case .background : return "background" 11 | default : return "unknown" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/kotlin/KotlinAssociatedObject.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | 5 | extension KotlinBase { 6 | 7 | static let queue = DispatchQueue.init(label: "KotlinBase-AssociatedObject") 8 | 9 | func getSetAssociatedObject(storageKey key: UnsafeRawPointer, block: () -> T) -> T { 10 | KotlinBase.queue.sync { 11 | if let existingValue = objc_getAssociatedObject(self, key) as? T { 12 | return existingValue 13 | } else { 14 | let newValue = block() 15 | 16 | objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 17 | return newValue 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/kotlin/KotlinExtensions+Bitcoin.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | import CryptoKit 4 | 5 | 6 | extension Bitcoin_kmpSatoshi { 7 | 8 | func toMilliSatoshi() -> Lightning_kmpMilliSatoshi { 9 | return Lightning_kmpMilliSatoshi(sat: self) 10 | } 11 | 12 | func toMsat() -> Int64 { 13 | return self.toLong() * Utils.Millisatoshis_Per_Satoshi 14 | } 15 | } 16 | 17 | extension Bitcoin_kmpTxId { 18 | 19 | func toHex() -> String { 20 | return self.value.toHex() 21 | } 22 | } 23 | 24 | extension Bitcoin_kmpByteVector32 { 25 | 26 | static func random() -> Bitcoin_kmpByteVector32 { 27 | 28 | let key = SymmetricKey(size: .bits256) // 256 / 8 = 32 29 | 30 | let data = key.withUnsafeBytes {(bytes: UnsafeRawBufferPointer) -> Data in 31 | return Data(bytes: bytes.baseAddress!, count: bytes.count) 32 | } 33 | 34 | return Bitcoin_kmpByteVector32(bytes: data.toKotlinByteArray()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/logging/LoggerFactory+Background.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// This file is **ONLY** for the Notify-Service-Extension (background process) 4 | /// 5 | extension LoggerFactory { 6 | class var friendlyProcessName: String { 7 | return friendlyProcessName_background 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/logging/LoggerFactory+Foreground.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// This file is **ONLY** for the main Phoenix app 4 | /// 5 | extension LoggerFactory { 6 | class var friendlyProcessName: String { 7 | return friendlyProcessName_foreground 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/nfc/extensions/ByteArrayConversions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Array where Element == UInt8 { 4 | 5 | func toData() -> Data { 6 | return Data(bytes: self, count: self.count) 7 | } 8 | } 9 | 10 | extension Data { 11 | 12 | func toByteArray() -> [UInt8] { 13 | var buffer = [UInt8]() 14 | self.withUnsafeBytes { 15 | buffer.append(contentsOf: $0) 16 | } 17 | return buffer 18 | } 19 | } 20 | 21 | extension FixedWidthInteger { 22 | 23 | func toByteArray() -> [UInt8] { 24 | withUnsafeBytes(of: self, Array.init) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/security/KeyStoreError.swift: -------------------------------------------------------------------------------- 1 | /** 2 | * Apple Sample Code: 3 | * https://developer.apple.com/documentation/cryptokit/storing_cryptokit_keys_in_the_keychain 4 | * 5 | * Abstract: 6 | * The interface required for conversion to a generic password keychain item. 7 | */ 8 | 9 | import Foundation 10 | 11 | /// An error we can throw when something goes wrong. 12 | struct KeyStoreError: Error, CustomStringConvertible { 13 | var message: String 14 | 15 | init(_ message: String) { 16 | self.message = message 17 | } 18 | 19 | public var description: String { 20 | return message 21 | } 22 | } 23 | 24 | extension OSStatus { 25 | 26 | /// A human readable message for the status. 27 | var message: String { 28 | return (SecCopyErrorMessageString(self, nil) as String?) ?? String(self) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/security/KeychainConstants.swift: -------------------------------------------------------------------------------- 1 | // Names of entries stored within the OS keychain: 2 | let keychain_accountName_keychain = "securityFile_keychain" 3 | let keychain_accountName_biometrics = "securityFile_biometrics" 4 | let keychain_accountName_softBiometrics = "biometrics" 5 | let keychain_accountName_passcodeFallback = "passcodeFallback" 6 | let keychain_accountName_lockPin = "customPin" 7 | let keychain_accountName_invalidLockPin = "invalidPin" 8 | let keychain_accountName_bip353Address = "bip353Address" 9 | let keychain_accountName_spendingPin = "spendingPin" 10 | let keychain_accountName_invalidSpendingPin = "invalidSpendingPin" 11 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/utils/Asserts.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | func assertMainThread() { 4 | assert(Thread.isMainThread, "Improper thread: expected main thread; Thread-unsafe code ahead") 5 | } 6 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/utils/CurrencyAmount.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct CurrencyAmount: Equatable { 4 | let currency: Currency 5 | let amount: Double 6 | } 7 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/utils/DelayedSave.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Combine 3 | 4 | class DelayedSave { 5 | 6 | private var cancellables = Set() 7 | private var timer: Timer? = nil 8 | private var needsSave: Bool = false 9 | private var saveAction: (() -> Void)? = nil 10 | 11 | init() { 12 | 13 | let nc = NotificationCenter.default 14 | nc.publisher(for: UIApplication.willResignActiveNotification).sink {[weak self] _ in 15 | self?.saveIfNeeded() 16 | }.store(in: &cancellables) 17 | } 18 | 19 | deinit { 20 | timer?.invalidate() 21 | } 22 | 23 | func save(withDelay delay: TimeInterval, action: @escaping () -> Void) { 24 | 25 | assert(Thread.isMainThread, "This function is restricted to the main-thread") 26 | 27 | needsSave = true 28 | saveAction = action 29 | 30 | timer?.invalidate() 31 | timer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: {[weak self] _ in 32 | self?.saveIfNeeded() 33 | }) 34 | } 35 | 36 | func saveIfNeeded() { 37 | if needsSave { 38 | needsSave = false 39 | 40 | timer?.invalidate() 41 | timer = nil 42 | 43 | saveAction?() 44 | saveAction = nil 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/utils/Either.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum Either{ 4 | case Left(A) 5 | case Right(B) 6 | } 7 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/utils/UnfairLock.swift: -------------------------------------------------------------------------------- 1 | /** 2 | * Credit: 3 | * - http://www.russbishop.net/the-law 4 | * - https://swiftrocks.com/thread-safety-in-swift 5 | * 6 | * Note: Once you drop support for iOS 15, you can switch to: 7 | * https://developer.apple.com/documentation/os/osallocatedunfairlock 8 | */ 9 | 10 | import Foundation 11 | 12 | final class UnfairLock { 13 | private var _lock: UnsafeMutablePointer 14 | 15 | init() { 16 | _lock = UnsafeMutablePointer.allocate(capacity: 1) 17 | _lock.initialize(to: os_unfair_lock()) 18 | } 19 | 20 | deinit { 21 | _lock.deallocate() 22 | } 23 | 24 | func locked(_ f: () throws -> ReturnValue) rethrows -> ReturnValue { 25 | os_unfair_lock_lock(_lock) 26 | defer { os_unfair_lock_unlock(_lock) } 27 | return try f() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/utils/ViewName.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Add this protocol to your view: 4 | /// ``` 5 | /// struct MyView: View, ViewName 6 | /// ``` 7 | /// 8 | /// And then you can quickly include the name of the view in log statements: 9 | /// ``` 10 | /// log.trace("[\(viewName)] onAppear()") 11 | /// ``` 12 | /// 13 | protocol ViewName { 14 | var viewName: String { get } 15 | } 16 | 17 | extension ViewName { 18 | 19 | var viewName: String { 20 | get { 21 | let thisType = type(of: self) 22 | return String(describing: thisType) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/utils/WalletIdentifier.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | struct WalletIdentifier { 5 | let chain: Bitcoin_kmpChain 6 | let encryptedNodeId: String 7 | 8 | init(chain: Bitcoin_kmpChain, encryptedNodeId: String) { 9 | self.chain = chain 10 | self.encryptedNodeId = encryptedNodeId 11 | } 12 | 13 | init(chain: Bitcoin_kmpChain, walletInfo: WalletManager.WalletInfo) { 14 | self.init(chain: chain, encryptedNodeId: walletInfo.encryptedNodeId) 15 | } 16 | 17 | var prefsKeySuffix: String { 18 | if chain.isMainnet() { 19 | return encryptedNodeId 20 | } else { 21 | return "\(encryptedNodeId)-\(chain.phoenixName)" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/utils/shapes.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct Line: Shape { 4 | func path(in rect: CGRect) -> Path { 5 | var path = Path() 6 | path.move(to: CGPoint(x: 0, y: 0)) 7 | path.addLine(to: CGPoint(x: rect.width, y: 0)) 8 | return path 9 | } 10 | } -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/compatibility/GeometryGroup_17.swift: -------------------------------------------------------------------------------- 1 | /// Good description of `.geometryGroup()` 2 | /// https://fatbobman.com/en/posts/mastring-geometrygroup/ 3 | 4 | import SwiftUI 5 | 6 | struct GeometryGroupViewModifier: ViewModifier { 7 | 8 | @ViewBuilder 9 | func body(content: Content) -> some View { 10 | if #available(iOS 17, *) { 11 | content.geometryGroup() 12 | } else { 13 | content 14 | } 15 | } 16 | } 17 | 18 | extension View { 19 | 20 | func _geometryGroup() -> some View { 21 | modifier(GeometryGroupViewModifier()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/compatibility/ListBackgroundColor.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | 4 | struct ListBackgroundColor: ViewModifier { 5 | let color: Color 6 | 7 | @ViewBuilder 8 | func body(content: Content) -> some View { 9 | content 10 | .background(color) 11 | .scrollContentBackground(.hidden) 12 | } 13 | } 14 | 15 | extension View { 16 | func listBackgroundColor(_ color: Color) -> some View { 17 | ModifiedContent( 18 | content: self, 19 | modifier: ListBackgroundColor(color: color) 20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/compatibility/VibrationFeedback.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | enum VibrationFeedbackType { 4 | case error 5 | 6 | @available(iOS 17.0, *) 7 | func convert() -> SensoryFeedback { 8 | switch self { 9 | case .error : return SensoryFeedback.error 10 | } 11 | } 12 | } 13 | 14 | struct VibrationFeedback: ViewModifier where T: Equatable { 15 | let type: VibrationFeedbackType 16 | let trigger: T 17 | 18 | @ViewBuilder 19 | func body(content: Content) -> some View { 20 | if #available(iOS 17.0, *) { 21 | content 22 | .sensoryFeedback(type.convert(), trigger: trigger) 23 | } else { 24 | content 25 | } 26 | } 27 | } 28 | 29 | extension View { 30 | func vibrationFeedback(_ type: VibrationFeedbackType, trigger: T) -> some View where T : Equatable { 31 | ModifiedContent( 32 | content: self, 33 | modifier: VibrationFeedback(type: type, trigger: trigger) 34 | ) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/configuration/advanced/wallet/UtxoWrapper.swift: -------------------------------------------------------------------------------- 1 | import Swift 2 | import PhoenixShared 3 | 4 | struct UtxoWrapper: Identifiable { 5 | let utxo: Lightning_kmpWalletState.Utxo 6 | let confirmationCount: Int64 7 | 8 | var amount: Bitcoin_kmpSatoshi { 9 | return utxo.amount 10 | } 11 | 12 | var txid: Bitcoin_kmpTxId { 13 | return utxo.previousTx.txid 14 | } 15 | 16 | var id: String { 17 | return utxo.id 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/configuration/fees/liquidity management/LiquidityFeeInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | struct LiquidityFeeParams { 5 | let amount: Bitcoin_kmpSatoshi 6 | let feerate: Lightning_kmpFeeratePerKw 7 | let fundingRate: Lightning_kmpLiquidityAdsFundingRate 8 | } 9 | 10 | struct LiquidityFeeEstimate { 11 | let minerFee: Bitcoin_kmpSatoshi 12 | let serviceFee: Bitcoin_kmpSatoshi 13 | } 14 | 15 | struct LiquidityFeeInfo { 16 | let params: LiquidityFeeParams 17 | let estimate: LiquidityFeeEstimate 18 | } 19 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/contacts/AddToContactsInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | struct AddToContactsInfo: Hashable { 5 | let offer: Lightning_kmpOfferTypesOffer? 6 | let address: String? 7 | } 8 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/content/RootView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct RootView: View { 4 | 5 | @ViewBuilder 6 | var body: some View { 7 | 8 | GeometryReader { geometry in 9 | ContentView() 10 | .frame(width: geometry.size.width, height: geometry.size.height, alignment: .center) 11 | .modifier(GlobalEnvironment.mainInstance()) 12 | .onAppear { 13 | GlobalEnvironment.deviceInfo._windowSize = geometry.size 14 | GlobalEnvironment.deviceInfo.windowSafeArea = geometry.safeAreaInsets 15 | } 16 | .onChange(of: geometry.size) { newSize in 17 | GlobalEnvironment.deviceInfo._windowSize = newSize 18 | } 19 | .onChange(of: geometry.safeAreaInsets) { newValue in 20 | GlobalEnvironment.deviceInfo.windowSafeArea = newValue 21 | } 22 | } // 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/html/AboutHTML.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | class AboutHTML: AnyHTML { 4 | 5 | init() { 6 | super.init(htmlFilename: "about", cssFilename: "common") 7 | } 8 | 9 | // Nothing else to override here. 10 | // The defaults work fine for us. 11 | } 12 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/html/Base.lproj/liquidity.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

10 | Phoenix allows you to receive payments on bitcoin's blockchain 11 | layer (L1) and bitcoin's lightning layer (L2). 12 |

13 |
    14 |
  • 15 | The blockchain layer (L1) is slower, 16 | and generally much more expensive (requires miner fees) 17 |
  • 18 |
  • 19 | The lightning layer (L2) is much faster, 20 | and generally much cheaper (especially for smaller payments) 21 |
  • 22 |
23 |

24 | When you receive a payment on L1, Phoenix will automatically 25 | move the funds to L2 IF the fees adhere to your 26 | configured fee policy. 27 |

28 |

29 | Payments you receive on L2 can be received instantly and for 30 | zero fees. However, occasionally an L1 operation is also 31 | required in order to manage the L2 payment channel. This can 32 | be done automatically IF the fees adhere to your 33 | configured fee policy. 34 |

35 | 36 | 37 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/html/LiquidityHTML.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | class LiquidityHTML: AnyHTML { 4 | 5 | init() { 6 | super.init(htmlFilename: "liquidity", cssFilename: "common") 7 | } 8 | 9 | // Nothing else to override here. 10 | // The defaults work fine for us. 11 | } 12 | 13 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/html/common.css: -------------------------------------------------------------------------------- 1 | /* Credits: 2 | * https://useyourloaf.com/blog/using-dynamic-type-with-web-views/ 3 | * https://useyourloaf.com/blog/supporting-dark-mode-in-wkwebview 4 | **/ 5 | 6 | :root { 7 | background: [[background_color]]; 8 | color: [[foreground_color]]; 9 | --link-color: [[link_color]]; 10 | } 11 | 12 | body { 13 | font: -apple-system-body; 14 | } 15 | 16 | a { 17 | color: var(--link-color); 18 | } 19 | 20 | p { 21 | margin-top: 0pt; 22 | margin-bottom: 0pt; 23 | padding-top: 5pt; 24 | padding-bottom: 10pt; 25 | } 26 | 27 | p.noBottomPadding { 28 | padding-bottom: 0pt; 29 | } 30 | 31 | ul { 32 | margin-top: 0; 33 | padding-top: 0; 34 | } 35 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/html/de.lproj/liquidity.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

10 | Phoenix allows you to receive payments on bitcoin's blockchain 11 | layer (L1) and bitcoin's lightning layer (L2). 12 |

13 |
    14 |
  • 15 | The blockchain layer (L1) is slower, 16 | and generally much more expensive (requires miner fees) 17 |
  • 18 |
  • 19 | The lightning layer (L2) is much faster, 20 | and generally much cheaper (especially for smaller payments) 21 |
  • 22 |
23 |

24 | When you receive a payment on L1, Phoenix will automatically 25 | move the funds to L2 IF the fees adhere to your 26 | configured fee policy. 27 |

28 |

29 | Payments you receive on L2 can be received instantly and for 30 | zero fees. However, occasionally an L1 operation is also 31 | required in order to manage the L2 payment channel. This can 32 | be done automatically IF the fees adhere to your 33 | configured fee policy. 34 |

35 | 36 | 37 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/inspect/Details/DetailsRowWrapper.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct DetailsRowWrapper: View { 4 | 5 | let identifier: String 6 | let keyColumnWidth: CGFloat 7 | let keyColumn: KeyColumn 8 | let valueColumn: ValueColumn 9 | 10 | init( 11 | identifier: String, 12 | keyColumnWidth: CGFloat, 13 | @ViewBuilder keyColumn keyColumnBuilder: () -> KeyColumn, 14 | @ViewBuilder valueColumn valueColumnBuilder: () -> ValueColumn 15 | ) { 16 | self.identifier = identifier 17 | self.keyColumnWidth = keyColumnWidth 18 | self.keyColumn = keyColumnBuilder() 19 | self.valueColumn = valueColumnBuilder() 20 | } 21 | 22 | @ViewBuilder 23 | var body: some View { 24 | 25 | InfoGridRow( 26 | identifier: identifier, 27 | vAlignment: .firstTextBaseline, 28 | hSpacing: 8, 29 | keyColumnWidth: keyColumnWidth, 30 | keyColumnAlignment: .trailing 31 | ) { 32 | keyColumn 33 | } valueColumn: { 34 | valueColumn.font(.callout) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/inspect/Details/DisplayAmounts.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct DisplayAmounts { 4 | let bitcoin: FormattedAmount 5 | let fiatCurrent: FormattedAmount? 6 | let fiatOriginal: FormattedAmount? 7 | } 8 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/inspect/Details/InlineSection.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct InlineSection: View { 4 | 5 | let header: Header 6 | let content: Content 7 | 8 | init( 9 | @ViewBuilder header headerBuilder: () -> Header, 10 | @ViewBuilder content contentBuilder: () -> Content 11 | ) { 12 | header = headerBuilder() 13 | content = contentBuilder() 14 | } 15 | 16 | @ViewBuilder 17 | var body: some View { 18 | 19 | VStack(alignment: HorizontalAlignment.center, spacing: 0) { 20 | header 21 | HStack(alignment: VerticalAlignment.center, spacing: 0) { 22 | VStack(alignment: HorizontalAlignment.leading, spacing: 12) { 23 | content 24 | } 25 | Spacer(minLength: 0) 26 | } 27 | .padding(.vertical, 10) 28 | .padding(.horizontal, 16) 29 | .background { 30 | Color(UIColor.secondarySystemGroupedBackground).cornerRadius(10) 31 | } 32 | .padding(.horizontal, 16) 33 | } 34 | .padding(.vertical, 16) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/main/MainView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import PhoenixShared 3 | 4 | fileprivate let filename = "MainView" 5 | #if DEBUG && true 6 | fileprivate var log = LoggerFactory.shared.logger(filename, .trace) 7 | #else 8 | fileprivate var log = LoggerFactory.shared.logger(filename, .warning) 9 | #endif 10 | 11 | enum HeaderButtonHeight: Preference {} 12 | 13 | struct MainView: View { 14 | 15 | static let idiom = UIDevice.current.userInterfaceIdiom 16 | 17 | @EnvironmentObject var popoverState: PopoverState 18 | 19 | @ViewBuilder 20 | var body: some View { 21 | Group { 22 | if MainView.idiom == .pad { 23 | MainView_Big() 24 | } else { 25 | MainView_Small() 26 | } 27 | }.onAppear { 28 | onAppear() 29 | } 30 | } 31 | 32 | func onAppear() { 33 | log.trace("onAppear()") 34 | 35 | if AppMigration.shared.didUpdate && AppMigration.shared.currentBuildNumber == "85" { 36 | if GroupPrefs.shared.isTorEnabled { 37 | popoverState.display(dismissable: false) { 38 | V85Popover() 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/main/NavigationCoordinator.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | class NavigationCoordinator: ObservableObject { 4 | @Published var path = NavigationPath() 5 | } 6 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/notifications/NoticeBox.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | fileprivate let filename = "NoticeBox" 4 | #if DEBUG && true 5 | fileprivate var log = LoggerFactory.shared.logger(filename, .trace) 6 | #else 7 | fileprivate var log = LoggerFactory.shared.logger(filename, .warning) 8 | #endif 9 | 10 | struct NoticeBox: View { 11 | 12 | let backgroundColor: Color? 13 | let content: Content 14 | 15 | init(@ViewBuilder builder: () -> Content) { 16 | self.backgroundColor = nil 17 | self.content = builder() 18 | } 19 | 20 | init(backgroundColor: Color?, @ViewBuilder builder: () -> Content) { 21 | self.backgroundColor = backgroundColor 22 | self.content = builder() 23 | } 24 | 25 | @ViewBuilder 26 | var body: some View { 27 | 28 | HStack(alignment: VerticalAlignment.top, spacing: 0) { 29 | content 30 | Spacer(minLength: 0) // ensure content takes up full width of screen 31 | } 32 | .padding(12) 33 | .background( 34 | RoundedRectangle(cornerRadius: 8) 35 | .fill(backgroundColor ?? Color.clear) 36 | ) 37 | .overlay( 38 | RoundedRectangle(cornerRadius: 8) 39 | .stroke(Color.appAccent, lineWidth: 1) 40 | ) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/onboarding/IntroContainer.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | fileprivate let filename = "IntroContainer" 4 | #if DEBUG && true 5 | fileprivate var log = LoggerFactory.shared.logger(filename, .trace) 6 | #else 7 | fileprivate var log = LoggerFactory.shared.logger(filename, .warning) 8 | #endif 9 | 10 | struct IntroContainer: View { 11 | 12 | @State var introFinished = false 13 | 14 | @StateObject var navCoordinator = NavigationCoordinator() 15 | 16 | @ViewBuilder 17 | var body: some View { 18 | 19 | NavigationStack(path: $navCoordinator.path) { 20 | content() 21 | } 22 | .environmentObject(navCoordinator) 23 | } 24 | 25 | @ViewBuilder 26 | func content() -> some View { 27 | 28 | ZStack { 29 | 30 | if introFinished { 31 | 32 | InitializationView() 33 | .zIndex(0) 34 | 35 | } else { 36 | 37 | IntroView(finish: introScreensFinished) 38 | .zIndex(1) // needed for proper animation 39 | .transition(.asymmetric( 40 | insertion : .identity, 41 | removal : .move(edge: .bottom) 42 | )) 43 | } 44 | } 45 | } 46 | 47 | func introScreensFinished() { 48 | log.trace("introScreenFinished()") 49 | 50 | withAnimation { 51 | introFinished = true 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/receive/InboundFeeWarning.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum InboundFeeWarning { 4 | case liquidityPolicyDisabled 5 | case overAbsoluteFee( 6 | canRequestLiquidity: Bool, 7 | maxAbsoluteFeeSats: Int64, 8 | swapFeeSats: Int64 9 | ) 10 | case overRelativeFee( 11 | canRequestLiquidity: Bool, 12 | maxRelativeFeePercent: Double, 13 | swapFeeSats: Int64 14 | ) 15 | case feeExpected( 16 | swapFeeSats: Int64 17 | ) 18 | case unknownFeeExpected; 19 | 20 | var type: InboundFeeWarningType { 21 | switch self { 22 | case .liquidityPolicyDisabled: 23 | return .willFail 24 | case .overAbsoluteFee(_, _, _): 25 | return .willFail 26 | case .overRelativeFee(_, _, _): 27 | return .willFail 28 | case .feeExpected(_): 29 | return .feeExpected 30 | case .unknownFeeExpected: 31 | return .feeExpected 32 | } 33 | } 34 | } 35 | 36 | enum InboundFeeWarningType { 37 | case willFail 38 | case feeExpected 39 | } 40 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/receive/SourceInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum SourceType { 4 | case text 5 | case image 6 | } 7 | 8 | struct SourceInfo { 9 | let type: SourceType 10 | let isDefault: Bool 11 | let title: String 12 | let subtitle: String? 13 | let callback: () -> Void 14 | } 15 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/send/FetchActivityNotice.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | fileprivate let filename = "FetchActivityNotice" 4 | #if DEBUG && true 5 | fileprivate var log = LoggerFactory.shared.logger(filename, .trace) 6 | #else 7 | fileprivate var log = LoggerFactory.shared.logger(filename, .warning) 8 | #endif 9 | 10 | /// Designed to go into a small sub-view 11 | /// 12 | struct FetchActivityNotice: View { 13 | 14 | let title: String 15 | let onCancel: () -> Void 16 | 17 | @ViewBuilder 18 | var body: some View { 19 | 20 | VStack(alignment: HorizontalAlignment.center, spacing: 8) { 21 | Text(title) 22 | 23 | ZStack { 24 | Divider() 25 | HorizontalActivity(color: .appAccent, diameter: 10, speed: 1.6) 26 | } 27 | .frame(width: 125, height: 10) 28 | 29 | Button { 30 | didTapCancel() 31 | } label: { 32 | Text("Cancel") 33 | } 34 | } 35 | .padding() 36 | .background(Color(UIColor.systemBackground)) 37 | .cornerRadius(16) 38 | } 39 | 40 | func didTapCancel() { 41 | log.trace("didTapCancel()") 42 | onCancel() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/send/MinerFeeInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | struct MinerFeeInfo { 5 | let pubKeyScript: Bitcoin_kmpByteVector? // For targets: .spliceOut 6 | let transaction: Bitcoin_kmpTransaction? // For targets: .expiredSwapIn, .finalWallet 7 | let feerate: Lightning_kmpFeeratePerKw 8 | let minerFee: Bitcoin_kmpSatoshi 9 | } 10 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/send/MsatRange.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | struct MsatRange { 5 | let min: Lightning_kmpMilliSatoshi 6 | let max: Lightning_kmpMilliSatoshi 7 | 8 | init(min: Lightning_kmpMilliSatoshi, max: Lightning_kmpMilliSatoshi) { 9 | self.min = min 10 | self.max = max 11 | } 12 | 13 | init(min: Int64, max: Int64) { 14 | self.min = Lightning_kmpMilliSatoshi(msat: min) 15 | self.max = Lightning_kmpMilliSatoshi(msat: max) 16 | } 17 | 18 | func contains(msat: Lightning_kmpMilliSatoshi) -> Bool { 19 | return contains(msat: msat.msat) 20 | } 21 | 22 | func contains(msat: Int64) -> Bool { 23 | return msat >= min.msat && msat <= max.msat 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/send/PriorityBoxStyle.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct PriorityBoxStyle: GroupBoxStyle { 4 | 5 | let width: CGFloat? 6 | let height: CGFloat? 7 | let disabled: Bool 8 | let selected: Bool 9 | let tapped: () -> Void 10 | 11 | func makeBody(configuration: GroupBoxStyleConfiguration) -> some View { 12 | VStack(alignment: HorizontalAlignment.center, spacing: 4) { 13 | configuration.label 14 | .font(.headline) 15 | configuration.content 16 | } 17 | .frame(width: width?.advanced(by: -16.0), height: height?.advanced(by: -16.0)) 18 | .padding(.all, 8) 19 | .background(RoundedRectangle(cornerRadius: 8, style: .continuous) 20 | .fill(Color(UIColor.quaternarySystemFill))) 21 | .overlay( 22 | RoundedRectangle(cornerRadius: 8) 23 | .stroke(selected ? Color.appAccent : Color(UIColor.quaternarySystemFill), lineWidth: 1) 24 | ) 25 | .onTapGesture { 26 | tapped() 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/style/CenterTopLineAlignment.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | // alignmentGuide explanation: 4 | // 5 | // The Toggle wants to vertically align its switch in the center of the body: 6 | // 7 | // |body| |switch| 8 | // 9 | // This works good when the body is a single line. 10 | // But with multiple lines it looks like: 11 | // 12 | // |line1| 13 | // |line2| |switch| 14 | // |line3| 15 | // 16 | // This isn't always what we want. 17 | // Instead we can use a custom VerticalAlignment to achieve this: 18 | // 19 | // |line1| |switch| 20 | // |line2| 21 | // |line3| 22 | // 23 | // A good resource on alignment guides can be found here: 24 | // https://swiftui-lab.com/alignment-guides/ 25 | 26 | extension VerticalAlignment { 27 | private enum CenterTopLineAlignment: AlignmentID { 28 | static func defaultValue(in d: ViewDimensions) -> CGFloat { 29 | return d[.bottom] 30 | } 31 | } 32 | 33 | static let centerTopLine = VerticalAlignment(CenterTopLineAlignment.self) 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/style/CheckboxToggleStyle.swift: -------------------------------------------------------------------------------- 1 | /// Inspiration for this code came from this wonderful blog: 2 | /// https://swiftuirecipes.com/blog/custom-toggle-checkbox-in-swiftui 3 | 4 | import Foundation 5 | import SwiftUI 6 | 7 | struct CheckboxToggleStyle: ToggleStyle where Img1: View, Img2: View { 8 | 9 | let onImage: Img1 10 | let offImage: Img2 11 | let action: (() -> Void)? 12 | 13 | init(onImage: Img1, offImage: Img2, action: (() -> Void)? = nil) { 14 | self.onImage = onImage 15 | self.offImage = offImage 16 | self.action = action 17 | } 18 | 19 | @Environment(\.isEnabled) var isEnabled 20 | 21 | func makeBody(configuration: Configuration) -> some View { 22 | Button(action: { 23 | configuration.isOn.toggle() 24 | if let action = action { 25 | action() 26 | } 27 | }, label: { 28 | Label { 29 | configuration.label 30 | } icon: { 31 | if configuration.isOn { 32 | onImage 33 | } else { 34 | offImage 35 | } 36 | } 37 | }) 38 | .buttonStyle(PlainButtonStyle()) // remove any implicit styling from the button 39 | .disabled(!isEnabled) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/style/InsetGroupBoxStyle.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | /// Makes a GroupBox look like a Section within a List with style `.insetGrouped` 4 | /// 5 | struct InsetGroupBoxStyle: GroupBoxStyle { 6 | 7 | func makeBody(configuration: GroupBoxStyleConfiguration) -> some View { 8 | VStack(alignment: .leading) { 9 | configuration.label 10 | configuration.content 11 | } 12 | .padding() 13 | .background(Color(.secondarySystemGroupedBackground)) 14 | .cornerRadius(10) 15 | .padding(.horizontal) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/style/LabelAlignment.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct LabelAlignment: View { 4 | 5 | let titleContent: () -> TitleContent 6 | let iconContent: () -> IconContent 7 | 8 | init( 9 | title: @escaping () -> TitleContent, 10 | icon: @escaping () -> IconContent 11 | ) { 12 | self.titleContent = title 13 | self.iconContent = icon 14 | } 15 | 16 | @ViewBuilder 17 | var body: some View { 18 | 19 | ZStack(alignment: Alignment.topLeading) { 20 | Label { 21 | Text(verbatim: "Label title").lineLimit(1).hidden() 22 | } icon: { 23 | iconContent() 24 | } 25 | Label { 26 | titleContent() 27 | } icon: { 28 | iconContent().hidden() 29 | } 30 | } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/style/ShakeEffect.swift: -------------------------------------------------------------------------------- 1 | // Credit: 2 | // https://www.objc.io/blog/2019/10/01/swiftui-shake-animation/ 3 | 4 | import SwiftUI 5 | 6 | struct Shake: GeometryEffect { 7 | var amount: CGFloat = 10 8 | var shakesPerUnit = 3 9 | var animatableData: CGFloat 10 | 11 | func effectValue(size: CGSize) -> ProjectionTransform { 12 | ProjectionTransform( 13 | CGAffineTransform( 14 | translationX: amount * sin(animatableData * .pi * CGFloat(shakesPerUnit)), 15 | y: 0 16 | ) 17 | ) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/style/ToggleAlignment.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ToggleAlignment: View { 4 | 5 | let descriptionContent: () -> DescriptionContent 6 | let toggleContent: () -> ToggleContent 7 | 8 | init( 9 | description: @escaping () -> DescriptionContent, 10 | toggle: @escaping () -> ToggleContent 11 | ) { 12 | self.descriptionContent = description 13 | self.toggleContent = toggle 14 | } 15 | 16 | @ViewBuilder 17 | var body: some View { 18 | 19 | HStack(alignment: VerticalAlignment.centerTopLine) { // <- Custom VerticalAlignment 20 | 21 | ZStack(alignment: Alignment.topLeading) { 22 | Text(verbatim: "Toggle alignment") 23 | .lineLimit(1) 24 | .hidden() 25 | .alignmentGuide(VerticalAlignment.centerTopLine) { (d: ViewDimensions) in 26 | d[VerticalAlignment.center] 27 | } 28 | 29 | descriptionContent() 30 | } 31 | 32 | Spacer() 33 | 34 | toggleContent() 35 | .padding(.trailing, 2) 36 | .alignmentGuide(VerticalAlignment.centerTopLine) { (d: ViewDimensions) in 37 | d[VerticalAlignment.center] 38 | } 39 | 40 | } // 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/transactions/PaymentsSection.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import PhoenixShared 3 | 4 | 5 | struct PaymentsSection: Identifiable { 6 | let year: Int 7 | let month: Int 8 | let name: String 9 | var payments: [WalletPaymentInfo] = [] 10 | 11 | var id: String { 12 | "\(year)-\(month)" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/updates/V85Popover.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | fileprivate let filename = "V85Popover" 4 | #if DEBUG && true 5 | fileprivate var log = LoggerFactory.shared.logger(filename, .trace) 6 | #else 7 | fileprivate var log = LoggerFactory.shared.logger(filename, .warning) 8 | #endif 9 | 10 | struct V85Popover: View { 11 | 12 | @EnvironmentObject var popoverState: PopoverState 13 | 14 | @ViewBuilder 15 | var body: some View { 16 | 17 | VStack(alignment: HorizontalAlignment.leading, spacing: 15) { 18 | 19 | Text("Version 2.5.0: Tor changes") 20 | .font(.headline) 21 | 22 | Text( 23 | """ 24 | Enabling Tor now requires installing a third-party Tor Proxy VPN app such as Orbot. 25 | 26 | This makes background payments much more reliable with Tor. 27 | 28 | Also Phoenix now always uses onion addresses for Lightning and Electrum \ 29 | connections when Tor is enabled. 30 | """ 31 | ) 32 | 33 | HStack(alignment: VerticalAlignment.center, spacing: 0) { 34 | Spacer() 35 | Button { 36 | popoverState.close() 37 | } label: { 38 | Text("OK").font(.title3) 39 | } 40 | } 41 | } 42 | .padding(.all) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/widgets/InfoPopoverWindow.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct InfoPopoverWindow: View { 4 | 5 | let content: () -> Content 6 | 7 | @ViewBuilder 8 | var body: some View { 9 | 10 | content() 11 | .padding(.all, 16) 12 | .background(Color(.systemBackground)) 13 | .cornerRadius(12) 14 | .shadow( 15 | color: Color(.label.withAlphaComponent(0.25)), 16 | radius: 40, 17 | x: 0, 18 | y: 4 19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/views/widgets/View+If.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | extension View { 4 | /// Applies the given transform if the given condition evaluates to `true`. 5 | /// - Parameters: 6 | /// - condition: The condition to evaluate. 7 | /// - transform: The transform to apply to the source `View`. 8 | /// - Returns: Either the original `View` or the modified `View` if the condition is `true`. 9 | @ViewBuilder func `if`(_ condition: Bool, transform: (Self) -> Content) -> some View { 10 | if condition { 11 | transform(self) 12 | } else { 13 | self 14 | } 15 | } 16 | 17 | /// Can be used when extra logic is needed. For example: 18 | /// ``` 19 | /// someView.modify { view in 20 | /// if #available(iOS 16.0, *) { 21 | /// view.foo() 22 | /// } else { 23 | /// view.bar() 24 | /// } 25 | /// } 26 | /// ``` 27 | func modify(@ViewBuilder _ modifier: (Self) -> T) -> some View { 28 | return modifier(self) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/xpc/XPC+Background.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// This file is **ONLY** for the Notify-Service-Extension (background process) 4 | /// 5 | extension XPC { 6 | public static let shared = XPC(actor: .notifySrvExt) 7 | } 8 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-ios/xpc/XPC+Foreground.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// This file is **ONLY** for the main Phoenix app 4 | /// 5 | extension XPC { 6 | public static let shared = XPC(actor: .mainApp) 7 | } 8 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-iosTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-iosUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-notifySrvExt/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.usernotifications.service 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).NotificationService 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /phoenix-ios/phoenix-notifySrvExt/phoenix-notifySrvExt.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.co.acinq.phoenix 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /phoenix-shared/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /phoenix-shared/src/androidMain/kotlin/fr/acinq/phoenix/data/androidElectrumRegtestConf.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.data 2 | 3 | import fr.acinq.lightning.io.TcpSocket 4 | import fr.acinq.lightning.utils.ServerAddress 5 | 6 | actual fun platformElectrumRegtestConf(): ServerAddress = ServerAddress(host = "10.0.2.2", port = 51002, tls = TcpSocket.TLS.DISABLED) 7 | -------------------------------------------------------------------------------- /phoenix-shared/src/androidMain/kotlin/fr/acinq/phoenix/db/SqlPaymentHooks.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.db 2 | 3 | import fr.acinq.lightning.utils.UUID 4 | import fr.acinq.phoenix.db.payments.CloudKitInterface 5 | import fr.acinq.phoenix.db.sqldelight.AppDatabase 6 | import fr.acinq.phoenix.db.sqldelight.PaymentsDatabase 7 | 8 | actual fun didSaveWalletPayment(id: UUID, database: PaymentsDatabase) {} 9 | actual fun didDeleteWalletPayment(id: UUID, database: PaymentsDatabase) {} 10 | actual fun didUpdateWalletPaymentMetadata(id: UUID, database: PaymentsDatabase) {} 11 | 12 | actual fun didSaveContact(contactId: UUID, database: PaymentsDatabase) {} 13 | actual fun didDeleteContact(contactId: UUID, database: PaymentsDatabase) {} 14 | 15 | actual fun makeCloudKitDb(appDb: SqliteAppDb, paymentsDb: SqlitePaymentsDb): CloudKitInterface? { 16 | return null 17 | } -------------------------------------------------------------------------------- /phoenix-shared/src/androidMain/kotlin/fr/acinq/phoenix/utils/platformAndroid.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.utils 2 | 3 | import android.content.Context 4 | 5 | 6 | actual class PlatformContext(val applicationContext: Context) 7 | 8 | actual fun getApplicationFilesDirectoryPath(ctx: PlatformContext): String = 9 | ctx.applicationContext.filesDir.absolutePath 10 | 11 | actual fun getDatabaseFilesDirectoryPath(ctx: PlatformContext): String? = null 12 | 13 | actual fun getApplicationCacheDirectoryPath(ctx: PlatformContext): String = 14 | ctx.applicationContext.cacheDir.absolutePath 15 | 16 | actual fun getTemporaryDirectoryPath(ctx: PlatformContext): String = 17 | ctx.applicationContext.cacheDir.absolutePath 18 | -------------------------------------------------------------------------------- /phoenix-shared/src/androidUnitTest/kotlin/fr/acinq/phoenix/db/SqliteChannelsDatabaseTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.db 18 | 19 | import app.cash.sqldelight.db.SqlDriver 20 | import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver 21 | import fr.acinq.phoenix.db.sqldelight.ChannelsDatabase 22 | 23 | actual fun testChannelsDriver(): SqlDriver { 24 | val driver: SqlDriver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY) 25 | ChannelsDatabase.Schema.create(driver) 26 | return driver 27 | } 28 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/controllers/MVI.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.controllers 2 | 3 | object MVI { 4 | 5 | abstract class Data { 6 | override fun toString(): String = this::class.simpleName ?: super.toString() 7 | } 8 | 9 | abstract class Model : Data() 10 | 11 | abstract class Intent : Data() 12 | 13 | abstract class Controller(val firstModel: M) { 14 | 15 | abstract fun subscribe(onModel: (M) -> Unit): () -> Unit 16 | 17 | abstract fun intent(intent: I) 18 | 19 | abstract fun stop() 20 | 21 | open class Mock(val model: M) : Controller(model) { 22 | override fun subscribe(onModel: (M) -> Unit): () -> Unit { 23 | onModel(model) 24 | return ({}) 25 | } 26 | override fun intent(intent: I) {} 27 | override fun stop() {} 28 | } 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/controllers/config/Configuration.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.controllers.config 2 | 3 | import fr.acinq.phoenix.controllers.MVI 4 | 5 | object Configuration { 6 | 7 | sealed class Model : MVI.Model() { 8 | object SimpleMode : Model() 9 | object FullMode : Model() 10 | } 11 | 12 | sealed class Intent : MVI.Intent() 13 | } 14 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/controllers/config/ElectrumConfiguration.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.controllers.config 2 | 3 | import fr.acinq.lightning.utils.Connection 4 | import fr.acinq.lightning.utils.ServerAddress 5 | import fr.acinq.phoenix.controllers.MVI 6 | import fr.acinq.phoenix.data.ElectrumConfig 7 | 8 | object ElectrumConfiguration { 9 | 10 | data class Model( 11 | val configuration: ElectrumConfig? = null, 12 | val currentServer: ServerAddress? = null, 13 | val connection: Connection = Connection.CLOSED(reason = null), 14 | val feeRate: Long = 0, 15 | val blockHeight: Int = 0, 16 | val tipTimestamp: Long = 0, 17 | val walletIsInitialized: Boolean = false, 18 | val error: Error? = null 19 | ) : MVI.Model() { 20 | fun isCustom() = configuration != null && configuration is ElectrumConfig.Custom 21 | } 22 | 23 | sealed class Intent : MVI.Intent() { 24 | data class UpdateElectrumServer(val config: ElectrumConfig.Custom?) : Intent() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/controllers/init/Initialization.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.controllers.init 2 | 3 | import fr.acinq.phoenix.controllers.MVI 4 | import fr.acinq.phoenix.utils.MnemonicLanguage 5 | 6 | 7 | object Initialization { 8 | 9 | sealed class Model : MVI.Model() { 10 | object Ready : Model() 11 | data class GeneratedWallet( 12 | val mnemonics: List, 13 | val language: MnemonicLanguage, 14 | val seed: ByteArray 15 | ) : Model() { 16 | override fun toString() = "GeneratedWallet" 17 | } 18 | } 19 | 20 | sealed class Intent : MVI.Intent() { 21 | data class GenerateWallet( 22 | val entropy: ByteArray, 23 | val language: MnemonicLanguage 24 | ) : Intent() { 25 | override fun toString() = "GenerateWallet" 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/controllers/main/Content.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.controllers.main 2 | 3 | import fr.acinq.phoenix.controllers.MVI 4 | 5 | object Content { 6 | 7 | sealed class Model : MVI.Model() { 8 | object Waiting : Model() 9 | object IsInitialized : Model() 10 | object NeedInitialization : Model() 11 | } 12 | 13 | sealed class Intent : MVI.Intent() 14 | 15 | } 16 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/controllers/main/Home.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.controllers.main 2 | 3 | import fr.acinq.lightning.MilliSatoshi 4 | import fr.acinq.phoenix.controllers.MVI 5 | 6 | object Home { 7 | 8 | data class Model( 9 | val balance: MilliSatoshi?, 10 | ) : MVI.Model() 11 | 12 | val emptyModel = Model( 13 | balance = null, 14 | ) 15 | 16 | sealed class Intent : MVI.Intent() 17 | } 18 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/controllers/main/HomeController.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.controllers.main 2 | 3 | import fr.acinq.lightning.logging.LoggerFactory 4 | import fr.acinq.phoenix.PhoenixBusiness 5 | import fr.acinq.phoenix.controllers.AppController 6 | import fr.acinq.phoenix.managers.BalanceManager 7 | import kotlinx.coroutines.launch 8 | 9 | 10 | class AppHomeController( 11 | loggerFactory: LoggerFactory, 12 | private val balanceManager: BalanceManager 13 | ) : AppController( 14 | loggerFactory = loggerFactory, 15 | firstModel = Home.emptyModel 16 | ) { 17 | constructor(business: PhoenixBusiness): this( 18 | loggerFactory = business.loggerFactory, 19 | balanceManager = business.balanceManager 20 | ) 21 | 22 | init { 23 | launch { 24 | balanceManager.balance.collect { 25 | model { copy(balance = it) } 26 | } 27 | } 28 | } 29 | 30 | override fun process(intent: Home.Intent) {} 31 | } 32 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/controllers/payments/Receive.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.controllers.payments 2 | 3 | import fr.acinq.lightning.MilliSatoshi 4 | import fr.acinq.phoenix.controllers.MVI 5 | 6 | object Receive { 7 | 8 | sealed class Model : MVI.Model() { 9 | object Awaiting : Model() 10 | object Generating: Model() 11 | data class Generated(val request: String, val paymentHash: String, val amount: MilliSatoshi?, val desc: String?): Model() 12 | } 13 | 14 | sealed class Intent : MVI.Intent() { 15 | data class Ask( 16 | val amount: MilliSatoshi?, 17 | val desc: String?, 18 | val expirySeconds: Long = 3600 * 24 * 7 // 7 days 19 | ) : Intent() 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/Wallet.kt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/Wallet.kt -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/WalletContext.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.data 2 | 3 | /** Contains contextual information for the wallet, fetched from https://acinq.co/phoenix/walletcontext.json. */ 4 | data class WalletContext( 5 | val isMempoolFull: Boolean, 6 | val androidLatestVersion: Int, 7 | val androidLatestCriticalVersion: Int, 8 | ) 9 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/WalletNotice.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.data 2 | 3 | data class WalletNotice(val message: String, val index: Int) -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/WalletPayment.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.data 2 | 3 | import fr.acinq.lightning.db.WalletPayment 4 | import fr.acinq.phoenix.data.lnurl.LnurlPay 5 | 6 | /** 7 | * Represents a payment & its associated metadata. 8 | */ 9 | data class WalletPaymentInfo( 10 | val payment: WalletPayment, 11 | val metadata: WalletPaymentMetadata, 12 | val contact: ContactInfo? 13 | ) { 14 | val id get() = payment.id 15 | } 16 | 17 | /** 18 | * Represents information from the `payments_metadata` table. 19 | */ 20 | data class WalletPaymentMetadata( 21 | val lnurl: LnurlPayMetadata? = null, 22 | val originalFiat: ExchangeRate.BitcoinPriceRate? = null, 23 | val userDescription: String? = null, 24 | val userNotes: String? = null, 25 | val lightningAddress: String? = null, 26 | val modifiedAt: Long? = null 27 | ) 28 | 29 | data class LnurlPayMetadata( 30 | val pay: LnurlPay.Intent, 31 | val description: String, 32 | val successAction: LnurlPay.Invoice.SuccessAction? 33 | ) { 34 | companion object { /* allow companion extensions */ } 35 | } 36 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/DbFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.db 18 | 19 | import app.cash.sqldelight.db.SqlDriver 20 | import fr.acinq.phoenix.utils.PlatformContext 21 | 22 | expect fun createChannelsDbDriver(ctx: PlatformContext, fileName: String): SqlDriver 23 | 24 | expect fun createPaymentsDbDriver(ctx: PlatformContext, fileName: String, onError: (String) -> Unit): SqlDriver 25 | 26 | expect fun createAppDbDriver(ctx: PlatformContext): SqlDriver 27 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/cloud/CloudHelper.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.db.cloud 2 | 3 | import io.ktor.util.* 4 | 5 | // Kotlin wants to encode a ByteArray like this: { 6 | // "fail": [123,34,112,97,121,109,101,110,116,82,101,113,117] 7 | // } 8 | // 9 | // Lol. If we don't use Cbor, then we should at least use Base64. 10 | 11 | fun ByteArray.b64Encode(): String { 12 | return this.encodeBase64() // io.ktor.util 13 | } 14 | 15 | fun String.b64Decode(): ByteArray { 16 | return this.decodeBase64Bytes() // io.ktor.util 17 | } 18 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/migrations/v10/json/OutpointSerializer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.db.migrations.v10.json 18 | 19 | import fr.acinq.bitcoin.OutPoint 20 | import fr.acinq.bitcoin.TxHash 21 | 22 | class OutpointSerializer : AbstractStringSerializer( 23 | name = "Outpoint", 24 | fromString = { serialized -> 25 | serialized.split(":").let { 26 | OutPoint(hash = TxHash(it[0]), index = it[1].toLong()) 27 | } 28 | }, 29 | toString = { outpoint -> "${outpoint.hash}:${outpoint.index}" } 30 | ) 31 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/migrations/v10/json/TxIdSerializer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.db.migrations.v10.json 18 | 19 | import fr.acinq.bitcoin.TxId 20 | 21 | object TxIdSerializer : AbstractStringSerializer( 22 | name = "TxId", 23 | toString = TxId::toString, 24 | fromString = ::TxId 25 | ) 26 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/CloudKitInterface.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.db.payments 2 | 3 | /* Cross-platform placeholder for CloudKitDb. */ 4 | interface CloudKitInterface { 5 | } -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/serialization/contacts/Serialization.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.db.serialization.contacts 2 | 3 | import fr.acinq.phoenix.data.ContactInfo 4 | 5 | object Serialization { 6 | 7 | fun serialize(contact: ContactInfo): ByteArray { 8 | return fr.acinq.phoenix.db.serialization.contacts.v1.Serialization.serialize(contact) 9 | } 10 | 11 | fun deserialize(bin: ByteArray): Result { 12 | return runCatching { 13 | when (val version = bin.first().toInt()) { 14 | 1 -> fr.acinq.phoenix.db.serialization.contacts.v1.Deserialization.deserialize(bin) 15 | else -> error("unknown version $version") 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/managers/NetworkMonitor.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.managers 2 | 3 | import fr.acinq.phoenix.utils.PlatformContext 4 | import kotlinx.coroutines.flow.StateFlow 5 | import fr.acinq.lightning.logging.LoggerFactory 6 | 7 | enum class NetworkState { 8 | Available, 9 | NotAvailable 10 | } 11 | 12 | expect class NetworkMonitor(loggerFactory: LoggerFactory, ctx: PlatformContext) { 13 | val networkState: StateFlow 14 | fun enable() 15 | fun disable() 16 | fun start() 17 | fun stop() 18 | } 19 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/utils/PlatformContext.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.utils 18 | 19 | 20 | expect class PlatformContext 21 | 22 | expect fun getApplicationFilesDirectoryPath(ctx: PlatformContext): String 23 | expect fun getDatabaseFilesDirectoryPath(ctx: PlatformContext): String? 24 | expect fun getApplicationCacheDirectoryPath(ctx: PlatformContext): String 25 | expect fun getTemporaryDirectoryPath(ctx: PlatformContext): String 26 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/utils/extensions/ChainExtensions.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.utils.extensions 2 | 3 | import fr.acinq.bitcoin.Chain 4 | 5 | /** 6 | * Value used by Phoenix for naming files relative to the [Chain]. 7 | * Specifically, testnet3 name must be "testnet", for historical reasons. 8 | */ 9 | val Chain.phoenixName: String 10 | get() = when (this) { 11 | Chain.Regtest -> "regtest" 12 | Chain.Signet -> "signet" 13 | Chain.Testnet3 -> "testnet" 14 | Chain.Testnet4 -> "testnet4" 15 | Chain.Mainnet -> "mainnet" 16 | } -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/utils/extensions/MiscExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.utils.extensions 18 | 19 | import fr.acinq.bitcoin.ByteVector32 20 | import fr.acinq.bitcoin.io.ByteArrayOutput 21 | import fr.acinq.lightning.serialization.OutputExtensions.writeUuid 22 | import fr.acinq.lightning.utils.UUID 23 | 24 | fun ByteVector32.deriveUUID(): UUID = UUID.fromBytes(this.take(16).toByteArray()) 25 | 26 | // TODO: use standard Uuid once migrated to kotlin 2 27 | fun UUID.toByteArray() = 28 | ByteArrayOutput().run { 29 | writeUuid(this@toByteArray) 30 | toByteArray() 31 | } -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/ExchangeRates.sq: -------------------------------------------------------------------------------- 1 | import fr.acinq.phoenix.data.ExchangeRate; 2 | 3 | CREATE TABLE IF NOT EXISTS exchange_rates ( 4 | fiat TEXT NOT NULL PRIMARY KEY, 5 | price REAL NOT NULL, 6 | type TEXT AS ExchangeRate.Type NOT NULL, 7 | source TEXT NOT NULL, 8 | updated_at INTEGER NOT NULL 9 | ); 10 | 11 | insert: 12 | INSERT INTO exchange_rates( 13 | fiat, price, type, source, updated_at 14 | ) VALUES (?, ?, ?, ?, ?); 15 | 16 | update: 17 | UPDATE exchange_rates SET price=?, type=?, source=?, updated_at=? WHERE fiat=?; 18 | 19 | get: 20 | SELECT * FROM exchange_rates WHERE fiat=?; 21 | 22 | list: 23 | SELECT * FROM exchange_rates; 24 | 25 | delete: 26 | DELETE FROM exchange_rates WHERE fiat=?; 27 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/KeyValueStore.sq: -------------------------------------------------------------------------------- 1 | -- Generic key/value store 2 | 3 | CREATE TABLE IF NOT EXISTS key_value_store ( 4 | key TEXT NOT NULL PRIMARY KEY, 5 | value BLOB NOT NULL, 6 | updated_at INTEGER NOT NULL 7 | ); 8 | 9 | get: 10 | SELECT * FROM key_value_store WHERE key = ?; 11 | 12 | exists: 13 | SELECT COUNT(*) FROM key_value_store WHERE key = ?; 14 | 15 | insert: 16 | INSERT INTO key_value_store(key, value, updated_at) VALUES (?, ?, ?); 17 | 18 | update: 19 | UPDATE key_value_store SET value = ?, updated_at = ? WHERE key = ?; 20 | 21 | delete: 22 | DELETE FROM key_value_store WHERE key = ?; -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/migrations/1.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v1 -> v2 2 | -- 3 | -- Changes: 4 | -- * Added table key_value_store 5 | 6 | CREATE TABLE IF NOT EXISTS key_value_store ( 7 | key TEXT NOT NULL PRIMARY KEY, 8 | value BLOB NOT NULL, 9 | updated_at INTEGER NOT NULL 10 | ); 11 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/migrations/2.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v2 -> v3 2 | -- 3 | -- Changes: 4 | -- * Deleted table bitcoin_price_rates 5 | -- * Added table exchange_rates 6 | 7 | DROP TABLE IF EXISTS bitcoin_price_rates; 8 | 9 | CREATE TABLE IF NOT EXISTS exchange_rates ( 10 | fiat TEXT NOT NULL PRIMARY KEY, 11 | price REAL NOT NULL, 12 | type TEXT NOT NULL, 13 | source TEXT NOT NULL, 14 | updated_at INTEGER NOT NULL 15 | ); 16 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/migrations/3.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v3 -> v4 2 | -- 3 | -- Changes: 4 | -- * add notifications table 5 | 6 | CREATE TABLE IF NOT EXISTS notifications ( 7 | id TEXT NOT NULL PRIMARY KEY, 8 | type_version TEXT AS NotificationTypeVersion NOT NULL, 9 | data_json BLOB NOT NULL, 10 | created_at INTEGER NOT NULL, 11 | read_at INTEGER DEFAULT NULL 12 | ); -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/migrations/4.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v4 -> v5 2 | -- 3 | -- Changes: 4 | -- * add contacts table 5 | -- * add contact_offers table 6 | 7 | CREATE TABLE IF NOT EXISTS contacts ( 8 | id TEXT NOT NULL PRIMARY KEY, 9 | name TEXT NOT NULL, 10 | photo_uri TEXT, 11 | created_at INTEGER NOT NULL, 12 | updated_at INTEGER DEFAULT NULL 13 | ); 14 | 15 | CREATE TABLE IF NOT EXISTS contact_offers ( 16 | offer_id BLOB NOT NULL PRIMARY KEY, 17 | contact_id TEXT NOT NULL, 18 | offer TEXT NOT NULL, 19 | created_at INTEGER NOT NULL, 20 | 21 | FOREIGN KEY(contact_id) REFERENCES contacts(id) 22 | ); 23 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/migrations/5.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v5 -> v6 2 | -- 3 | -- Changes: 4 | -- * add use_offer_key flag to the contacts table. By default, a contact is trusted. 5 | 6 | ALTER TABLE contacts 7 | ADD COLUMN use_offer_key INTEGER AS Boolean DEFAULT 1 NOT NULL; -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/migrations/6.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v6 -> v7 2 | -- 3 | -- Changes: 4 | -- * Added table cloudkit_contacts_metadata 5 | -- * Added index on table cloudkit_contacts_metadata 6 | -- * Added table cloudkit_contacts_queue 7 | -- 8 | -- See CloudKitContacts.sq for more details. 9 | 10 | CREATE TABLE IF NOT EXISTS cloudkit_contacts_metadata ( 11 | id TEXT NOT NULL PRIMARY KEY, 12 | record_creation INTEGER NOT NULL, 13 | record_blob BLOB NOT NULL 14 | ); 15 | 16 | CREATE INDEX IF NOT EXISTS record_creation_idx 17 | ON cloudkit_contacts_metadata(record_creation); 18 | 19 | CREATE TABLE IF NOT EXISTS cloudkit_contacts_queue ( 20 | rowid INTEGER PRIMARY KEY, 21 | id TEXT NOT NULL, 22 | date_added INTEGER NOT NULL 23 | ); 24 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/appdb/fr/acinq/phoenix/db/sqldelight/migrations/7.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v7 -> v8 2 | -- 3 | -- Changes: 4 | -- * Migrating contacts to paymentsDb 5 | -- 6 | 7 | DROP INDEX IF EXISTS contact_id_index; 8 | 9 | --- The original `contact_offers` table has a FOREIGN KEY constraint. 10 | --- This is going to cause a problem when we rename the contacts table. 11 | --- And there's no way to drop a constraint in sqlite. 12 | --- So we need to migrate the old table to a new one without the constraint. 13 | CREATE TABLE IF NOT EXISTS contact_offers_old ( 14 | offer_id BLOB NOT NULL PRIMARY KEY, 15 | contact_id TEXT NOT NULL, 16 | offer TEXT NOT NULL, 17 | created_at INTEGER NOT NULL 18 | ); 19 | INSERT INTO contact_offers_old SELECT * FROM contact_offers; 20 | DROP TABLE IF EXISTS contact_offers; 21 | 22 | ALTER TABLE contacts RENAME TO contacts_old; 23 | 24 | DROP INDEX IF EXISTS record_creation_idx; 25 | ALTER TABLE cloudkit_contacts_metadata RENAME TO cloudkit_contacts_metadata_old; 26 | DROP TABLE IF EXISTS cloudkit_contacts_queue; 27 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/fr/acinq/phoenix/db/sqldelight/Contacts.sq: -------------------------------------------------------------------------------- 1 | import fr.acinq.lightning.utils.UUID; 2 | import fr.acinq.phoenix.data.ContactInfo; 3 | 4 | CREATE TABLE IF NOT EXISTS contacts ( 5 | id BLOB AS UUID NOT NULL PRIMARY KEY, 6 | data BLOB AS ContactInfo NOT NULL, 7 | created_at INTEGER NOT NULL, 8 | updated_at INTEGER DEFAULT NULL 9 | ); 10 | 11 | listContacts: 12 | SELECT data 13 | FROM contacts; 14 | 15 | getContact: 16 | SELECT data 17 | FROM contacts 18 | WHERE id = :contactId; 19 | 20 | scanContacts: 21 | SELECT id, created_at FROM contacts; 22 | 23 | existsContact: 24 | SELECT COUNT(*) FROM contacts 25 | WHERE id = ?; 26 | 27 | insertContact: 28 | INSERT INTO contacts(id, data, created_at, updated_at) 29 | VALUES (:id, :data, :createdAt, :updatedAt); 30 | 31 | updateContact: 32 | UPDATE contacts SET data=:data, updated_at=:updatedAt 33 | WHERE id=:contactId; 34 | 35 | deleteContact: 36 | DELETE FROM contacts WHERE id=:contactId; 37 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/fr/acinq/phoenix/db/sqldelight/OnChainTransactions.sq: -------------------------------------------------------------------------------- 1 | import fr.acinq.bitcoin.ByteVector32; 2 | import fr.acinq.bitcoin.TxId; 3 | import fr.acinq.lightning.utils.UUID; 4 | 5 | CREATE TABLE on_chain_txs ( 6 | payment_id BLOB AS UUID NOT NULL PRIMARY KEY, 7 | tx_id BLOB AS TxId NOT NULL, 8 | confirmed_at INTEGER, 9 | locked_at INTEGER 10 | ); 11 | 12 | CREATE INDEX on_chain_txs_tx_id ON on_chain_txs(tx_id); 13 | 14 | insert: 15 | INSERT INTO on_chain_txs( 16 | payment_id, 17 | tx_id, 18 | confirmed_at, 19 | locked_at) 20 | VALUES (?, ?, ?, ?); 21 | 22 | setConfirmed: 23 | UPDATE on_chain_txs 24 | SET confirmed_at=? 25 | WHERE tx_id=?; 26 | 27 | setLocked: 28 | UPDATE on_chain_txs 29 | SET locked_at=? 30 | WHERE tx_id=?; 31 | 32 | listUnconfirmed: 33 | SELECT tx_id 34 | FROM on_chain_txs 35 | WHERE confirmed_at IS NULL; 36 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/1.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v1 -> v2 2 | -- 3 | -- Changes: 4 | -- * Added table cloudkit_payments_metadata 5 | -- * Added table cloudkit_payments_queue 6 | 7 | CREATE TABLE IF NOT EXISTS cloudkit_payments_metadata ( 8 | type INTEGER NOT NULL, 9 | id TEXT NOT NULL, 10 | unpadded_size INTEGER NOT NULL, 11 | record_creation INTEGER NOT NULL, 12 | record_blob BLOB NOT NULL, 13 | PRIMARY KEY (type, id) 14 | ); 15 | 16 | CREATE INDEX IF NOT EXISTS record_creation_idx 17 | ON cloudkit_payments_metadata(record_creation); 18 | 19 | CREATE TABLE IF NOT EXISTS cloudkit_payments_queue ( 20 | rowid INTEGER PRIMARY KEY, 21 | type INTEGER NOT NULL, 22 | id TEXT NOT NULL, 23 | date_added INTEGER NOT NULL 24 | ); -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/10.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v10 -> v11 2 | -- 3 | -- This is a code migration, see AfterVersion10.kt 4 | 5 | -- incoming payments 6 | CREATE TABLE payments_incoming ( 7 | id BLOB AS UUID NOT NULL PRIMARY KEY, 8 | payment_hash BLOB AS ByteVector32 UNIQUE, 9 | tx_id BLOB AS TxId, 10 | created_at INTEGER NOT NULL, 11 | received_at INTEGER, 12 | data BLOB AS IncomingPayment NOT NULL 13 | ); 14 | 15 | CREATE INDEX payments_incoming_payment_hash_idx ON payments_incoming(payment_hash); 16 | CREATE INDEX payments_incoming_tx_id_idx ON payments_incoming(tx_id); 17 | 18 | -- Create indexes to optimize the queries in AggregatedQueries. 19 | -- Tip: Use "explain query plan" to ensure they're actually being used. 20 | CREATE INDEX payments_incoming_filter_idx 21 | ON payments_incoming(received_at) 22 | WHERE received_at IS NOT NULL; -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/2.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v2 -> v3 2 | -- 3 | -- Changes: 4 | -- * Added table payments_metadata 5 | 6 | import fr.acinq.phoenix.db.payments.LnurlBase; 7 | import fr.acinq.phoenix.db.payments.LnurlMetadata; 8 | import fr.acinq.phoenix.db.payments.LnurlSuccessAction; 9 | 10 | CREATE TABLE IF NOT EXISTS payments_metadata ( 11 | type INTEGER NOT NULL, 12 | id TEXT NOT NULL, 13 | lnurl_base_type TEXT AS LnurlBase.TypeVersion, 14 | lnurl_base_blob BLOB, 15 | lnurl_description TEXT, 16 | lnurl_metadata_type TEXT AS LnurlMetadata.TypeVersion, 17 | lnurl_metadata_blob BLOB, 18 | lnurl_successAction_type TEXT AS LnurlSuccessAction.TypeVersion, 19 | lnurl_successAction_blob BLOB, 20 | user_description TEXT, 21 | PRIMARY KEY (type, id) 22 | ); 23 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/3.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v3 -> v4 2 | -- 3 | -- Changes: 4 | -- * Added column: payments_metadata.user_notes 5 | -- * Added column: payments_metadata.modified_at 6 | -- * Added indexes to improve performance of listAllPaymentsOrder query 7 | 8 | ALTER TABLE payments_metadata ADD COLUMN user_notes TEXT DEFAULT NULL; 9 | ALTER TABLE payments_metadata ADD COLUMN modified_at INTEGER DEFAULT NULL; 10 | 11 | CREATE INDEX IF NOT EXISTS incoming_payments_created_at_idx ON incoming_payments(created_at); 12 | CREATE INDEX IF NOT EXISTS outgoing_payments_created_at_idx ON outgoing_payments(created_at); 13 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/4.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v4 -> v5 2 | -- 3 | -- Changes: 4 | -- * Added column: payments_metadata.original_fiat_type 5 | -- * Added column: payments_metadata.original_fiat_rate 6 | 7 | ALTER TABLE payments_metadata ADD COLUMN original_fiat_type TEXT DEFAULT NULL; 8 | ALTER TABLE payments_metadata ADD COLUMN original_fiat_rate REAL DEFAULT NULL; 9 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/5.sqm: -------------------------------------------------------------------------------- 1 | import fr.acinq.phoenix.db.payments.OutgoingPartClosingInfoTypeVersion; 2 | 3 | -- Migration: v5 -> v6 4 | -- 5 | -- Changes: 6 | -- * Add a new table that stores the transactions closing a lightning channel, represented 7 | -- as parts of an outgoing payment. 8 | -- * Add an index on parent_id in the closing txs table. 9 | 10 | CREATE TABLE IF NOT EXISTS outgoing_payment_closing_tx_parts ( 11 | part_id TEXT NOT NULL PRIMARY KEY, 12 | part_parent_id TEXT NOT NULL, 13 | part_tx_id BLOB NOT NULL, 14 | part_amount_sat INTEGER NOT NULL, 15 | part_closing_info_type TEXT AS OutgoingPartClosingInfoTypeVersion NOT NULL, 16 | part_closing_info_blob BLOB NOT NULL, 17 | part_created_at INTEGER NOT NULL, 18 | 19 | FOREIGN KEY(part_parent_id) REFERENCES outgoing_payments(id) 20 | ); 21 | 22 | CREATE INDEX IF NOT EXISTS parent_id_idx ON outgoing_payment_closing_tx_parts(part_parent_id); -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/6.sqm: -------------------------------------------------------------------------------- 1 | -- Migration: v6 -> v7 2 | -- 3 | -- Changes: 4 | -- * Removed index: received_amount_msat_idx 5 | -- * Replaced index: incoming_payments_created_at_idx -> incoming_payments_filter_idx 6 | -- * Replaced index: outgoing_payments_created_at_idx -> outgoing_payments_filter_idx 7 | 8 | DROP INDEX IF EXISTS received_amount_msat_idx; 9 | 10 | DROP INDEX IF EXISTS incoming_payments_created_at_idx; 11 | CREATE INDEX IF NOT EXISTS incoming_payments_filter_idx 12 | ON incoming_payments(received_at) 13 | WHERE received_at IS NOT NULL; 14 | 15 | DROP INDEX IF EXISTS outgoing_payments_created_at_idx; 16 | CREATE INDEX IF NOT EXISTS outgoing_payments_filter_idx 17 | ON outgoing_payments(completed_at); 18 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/8.sqm: -------------------------------------------------------------------------------- 1 | import fr.acinq.phoenix.db.payments.InboundLiquidityLeaseTypeVersion; 2 | 3 | -- Migration: v8 -> v9 4 | -- 5 | -- Changes: 6 | -- * add a new inbound_liquidity_outgoing_payments table to store inbound liquidity payments 7 | 8 | CREATE TABLE IF NOT EXISTS inbound_liquidity_outgoing_payments ( 9 | id TEXT NOT NULL PRIMARY KEY, 10 | mining_fees_sat INTEGER NOT NULL, 11 | channel_id BLOB NOT NULL, 12 | tx_id BLOB NOT NULL, 13 | lease_type TEXT AS InboundLiquidityLeaseTypeVersion NOT NULL, 14 | lease_blob BLOB NOT NULL, 15 | created_at INTEGER NOT NULL, 16 | confirmed_at INTEGER DEFAULT NULL, 17 | locked_at INTEGER DEFAULT NULL 18 | ); 19 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonMain/sqldelight/paymentsdb/migrations/9.sqm: -------------------------------------------------------------------------------- 1 | import fr.acinq.phoenix.db.payments.InboundLiquidityLeaseTypeVersion; 2 | 3 | -- Migration: v9 -> v10 4 | -- 5 | -- Changes: 6 | -- * Added a new column [payment_details_type] in table [inbound_liquidity_outgoing_payments] 7 | 8 | ALTER TABLE inbound_liquidity_outgoing_payments ADD COLUMN payment_details_type TEXT DEFAULT NULL; 9 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/utils/TestLoggerFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.utils 18 | 19 | import co.touchlab.kermit.CommonWriter 20 | import co.touchlab.kermit.NoTagFormatter 21 | import co.touchlab.kermit.Severity 22 | import co.touchlab.kermit.loggerConfigInit 23 | import fr.acinq.lightning.logging.LoggerFactory 24 | 25 | val testLoggerFactory: LoggerFactory by lazy { 26 | LoggerFactory( 27 | config = loggerConfigInit( 28 | logWriters = arrayOf(CommonWriter(NoTagFormatter)), 29 | minSeverity = Severity.Info 30 | ) 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /phoenix-shared/src/commonTest/resources/sampledbs/v1/payments-testnet-a224978853d2f4c94ac8e2dbb2acf8344e0146d0.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-shared/src/commonTest/resources/sampledbs/v1/payments-testnet-a224978853d2f4c94ac8e2dbb2acf8344e0146d0.sqlite -------------------------------------------------------------------------------- /phoenix-shared/src/commonTest/resources/sampledbs/v1/payments-testnet-fedc36138a62ceadc8a93861d2c46f5ca5e8b418.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-shared/src/commonTest/resources/sampledbs/v1/payments-testnet-fedc36138a62ceadc8a93861d2c46f5ca5e8b418.sqlite -------------------------------------------------------------------------------- /phoenix-shared/src/commonTest/resources/sampledbs/v10/payments-testnet-28903aff.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-shared/src/commonTest/resources/sampledbs/v10/payments-testnet-28903aff.sqlite -------------------------------------------------------------------------------- /phoenix-shared/src/commonTest/resources/sampledbs/v10/payments-testnet-6a5e6f.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-shared/src/commonTest/resources/sampledbs/v10/payments-testnet-6a5e6f.sqlite -------------------------------------------------------------------------------- /phoenix-shared/src/commonTest/resources/sampledbs/v10/payments-testnet-f921bddf.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-shared/src/commonTest/resources/sampledbs/v10/payments-testnet-f921bddf.sqlite -------------------------------------------------------------------------------- /phoenix-shared/src/commonTest/resources/sampledbs/v6/payments-testnet-700486fc7a90d5922d6f993f2941ab9f9f1a9d85.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ACINQ/phoenix/b26ab3a809122467a63c6c17efd5f3d5d1bb3b4f/phoenix-shared/src/commonTest/resources/sampledbs/v6/payments-testnet-700486fc7a90d5922d6f993f2941ab9f9f1a9d85.sqlite -------------------------------------------------------------------------------- /phoenix-shared/src/iosMain/kotlin/fr/acinq/phoenix/data/iosElectrumRegtestConf.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.data 2 | 3 | import fr.acinq.lightning.io.TcpSocket 4 | import fr.acinq.lightning.utils.ServerAddress 5 | 6 | actual fun platformElectrumRegtestConf(): ServerAddress = ServerAddress(host = "127.0.0.1", port = 51002, TcpSocket.TLS.DISABLED) 7 | -------------------------------------------------------------------------------- /phoenix-shared/src/iosMain/kotlin/fr/acinq/phoenix/db/CloudKitDb.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.db 2 | 3 | import fr.acinq.phoenix.db.payments.* 4 | import kotlinx.coroutines.* 5 | 6 | class CloudKitDb( 7 | appDb: SqliteAppDb, 8 | paymentsDb: SqlitePaymentsDb 9 | ): CloudKitInterface, CoroutineScope by MainScope() { 10 | 11 | val contacts = CloudKitContactsDb(paymentsDb) 12 | val payments = CloudKitPaymentsDb(paymentsDb) 13 | } 14 | -------------------------------------------------------------------------------- /phoenix-shared/src/iosMain/kotlin/fr/acinq/phoenix/utils/PassthruLogWriter.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.utils 2 | 3 | import co.touchlab.kermit.LogWriter 4 | import co.touchlab.kermit.Severity 5 | 6 | class PassthruLogWriter( 7 | val logger: (Severity, String, String) -> Unit 8 | ) : LogWriter() { 9 | 10 | constructor(ctx: PlatformContext) : this( 11 | logger = ctx.logger!! 12 | ) 13 | 14 | override fun log(severity: Severity, message: String, tag: String, throwable: Throwable?) { 15 | logger(severity, message, tag) 16 | } 17 | } -------------------------------------------------------------------------------- /phoenix-shared/src/iosMain/kotlin/fr/acinq/phoenix/utils/PhoenixExposure.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.utils 2 | 3 | import fr.acinq.lightning.MilliSatoshi 4 | import fr.acinq.lightning.utils.UUID 5 | import fr.acinq.phoenix.data.ContactInfo 6 | import fr.acinq.phoenix.data.LocalChannelInfo 7 | import fr.acinq.phoenix.data.availableForReceive 8 | import fr.acinq.phoenix.data.canRequestLiquidity 9 | import fr.acinq.phoenix.data.inFlightPaymentsCount 10 | 11 | /** 12 | * Workarounds for various shortcomings between Kotlin and iOS. 13 | */ 14 | 15 | //fun NodeParamsManager.Companion._liquidityLeaseRate(amount: Satoshi): LiquidityAds_LeaseRate { 16 | // val result = this.liquidityLeaseRate(amount) 17 | // return LiquidityAds_LeaseRate(result) 18 | //} 19 | 20 | fun LocalChannelInfo.Companion.availableForReceive( 21 | channels: List 22 | ): MilliSatoshi? { 23 | return channels.availableForReceive() 24 | } 25 | 26 | fun LocalChannelInfo.Companion.canRequestLiquidity( 27 | channels: List 28 | ): Boolean { 29 | return channels.canRequestLiquidity() 30 | } 31 | 32 | fun LocalChannelInfo.Companion.inFlightPaymentsCount( 33 | channels: List 34 | ): Int { 35 | return channels.inFlightPaymentsCount() 36 | } -------------------------------------------------------------------------------- /phoenix-shared/src/iosMain/kotlin/fr/acinq/phoenix/utils/platformIos.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.utils 2 | 3 | import co.touchlab.kermit.Severity 4 | import platform.Foundation.* 5 | 6 | actual class PlatformContext( 7 | val logger: ((Severity, String, String) -> Unit)? = null 8 | ) 9 | 10 | actual fun getApplicationFilesDirectoryPath(ctx: PlatformContext): String = 11 | NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0] as String 12 | 13 | actual fun getApplicationCacheDirectoryPath(ctx: PlatformContext): String = 14 | NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, true)[0] as String 15 | 16 | actual fun getDatabaseFilesDirectoryPath(ctx: PlatformContext): String? { 17 | return NSFileManager.defaultManager.containerURLForSecurityApplicationGroupIdentifier( 18 | groupIdentifier = "group.co.acinq.phoenix" 19 | )?.URLByAppendingPathComponent( 20 | pathComponent = "databases", 21 | isDirectory = true 22 | )?.path 23 | } 24 | 25 | actual fun getTemporaryDirectoryPath(ctx: PlatformContext): String = 26 | NSTemporaryDirectory() 27 | -------------------------------------------------------------------------------- /phoenix-shared/src/iosTest/kotlin/fr/acinq/phoenix/data/ElectrumServersTest.kt: -------------------------------------------------------------------------------- 1 | package fr.acinq.phoenix.data 2 | 3 | import fr.acinq.lightning.utils.ServerAddress 4 | 5 | actual suspend fun connect(server: ServerAddress) { 6 | } -------------------------------------------------------------------------------- /phoenix-shared/src/iosTest/kotlin/fr/acinq/phoenix/db/PaymentsDbMigrationTest.ios.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 ACINQ SAS 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package fr.acinq.phoenix.db 18 | 19 | import fr.acinq.phoenix.utils.PlatformContext 20 | import okio.Path 21 | import kotlin.collections.List 22 | 23 | actual abstract class UsingContextTest { 24 | actual fun getPlatformContext(): PlatformContext = PlatformContext() 25 | actual fun setUpDatabase(context: PlatformContext, databasePaths: List) { 26 | TODO() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | maven(url = "https://maven.pkg.jetbrains.space/public/p/compose/dev") 6 | } 7 | } 8 | 9 | rootProject.name = "phoenix" 10 | 11 | // Android app may be skipped to make life easier on iOS developers. 12 | // Use `skip.android` in `local.properties` to define whether android app are built or not. 13 | // By default, Android apps are NOT skipped. 14 | val skipAndroid = File("$rootDir/local.properties").takeIf { it.exists() } 15 | ?.inputStream()?.use { java.util.Properties().apply { load(it) } } 16 | ?.run { getProperty("skip.android", "false")?.toBoolean() } 17 | ?: false 18 | 19 | // Inject the skip value in System properties so that it can be used in other gradle build files. 20 | System.setProperty("includeAndroid", (!skipAndroid).toString()) 21 | 22 | // The shared app is always included. 23 | include(":phoenix-shared") 24 | 25 | // Android apps are optional. 26 | if (!skipAndroid) { 27 | include(":phoenix-android") 28 | } 29 | --------------------------------------------------------------------------------