mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-08-11 00:47:42 +00:00
Fixes: Can not init transactions after recovery from backup, fix retry of SEND transaction.
This commit is contained in:
@@ -32,7 +32,7 @@ notifee.registerForegroundService(async (notification) => {
|
||||
try {
|
||||
|
||||
if(notification.data.task === HANDLE_NWC_REQUEST_TASK) {
|
||||
log.debug(`[registerForegroundService] Submitting task ${HANDLE_NWC_REQUEST_TASK} to the queue.`)
|
||||
log.info(`[registerForegroundService] Submitting task ${HANDLE_NWC_REQUEST_TASK} to the queue.`)
|
||||
|
||||
const {nwcStore} = rootStoreInstance
|
||||
// if an app is in killed state, state is not loaded
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "minibits_wallet",
|
||||
"version": "0.1.11-beta.5",
|
||||
"version": "0.1.11-beta.6",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"android:clean": "cd android && ./gradlew clean",
|
||||
|
||||
@@ -194,6 +194,11 @@ export const WalletProfileStoreModel = types
|
||||
}),
|
||||
setDevice: flow(function* setDevice(device: string) {
|
||||
try {
|
||||
if(!self.pubkey) {
|
||||
// skip call for new installs without a profile
|
||||
return
|
||||
}
|
||||
|
||||
yield MinibitsClient.updateDeviceToken(self.pubkey, {deviceToken: device})
|
||||
self.device = device
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -22,11 +22,10 @@ import {
|
||||
} from '../components'
|
||||
import {useHeader} from '../utils/useHeader'
|
||||
import AppError, { Err } from '../utils/AppError'
|
||||
import { Database, KeyChain, log, MinibitsClient, NostrClient } from '../services'
|
||||
import { Database, KeyChain, log, MinibitsClient } from '../services'
|
||||
import Clipboard from '@react-native-clipboard/clipboard'
|
||||
import { useStores } from '../models'
|
||||
import { rootStoreInstance, useStores } from '../models'
|
||||
import {MnemonicInput} from './Recovery/MnemonicInput'
|
||||
import { TransactionStatus } from '../models/Transaction'
|
||||
import { MINIBITS_MINT_URL, MINIBITS_NIP05_DOMAIN } from '@env'
|
||||
import { delay } from '../utils/utils'
|
||||
import { applySnapshot} from 'mobx-state-tree'
|
||||
@@ -36,6 +35,8 @@ import { translate } from '../i18n'
|
||||
import { ProofsStoreSnapshot } from '../models/ProofsStore'
|
||||
import { MintsStoreSnapshot } from '../models/MintsStore'
|
||||
import { ContactsStoreSnapshot } from '../models/ContactsStore'
|
||||
import { CashuMint, MintActiveKeys } from '@cashu/cashu-ts'
|
||||
import { MintUnit } from '../services/wallet/currency'
|
||||
|
||||
|
||||
if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
|
||||
@@ -224,12 +225,30 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
|
||||
|
||||
// import wallet snapshot into the state
|
||||
// const rootStore = rootStoreInstance
|
||||
|
||||
// hydrate mint keys back to the backup as they are stripped from backup
|
||||
for (const mint of walletSnapshot.mintsStore.mints) {
|
||||
const cashuMint = new CashuMint(mint.mintUrl)
|
||||
const keysResult: MintActiveKeys = await cashuMint.getKeys()
|
||||
const {keysets: keys} = keysResult
|
||||
|
||||
for(const key of keys) {
|
||||
if(!key.unit) {
|
||||
key.unit = 'sat'
|
||||
}
|
||||
|
||||
log.trace('[importWallet] Hydrating keys for', {keysetId: key.id})
|
||||
mint.keys.push(key)
|
||||
}
|
||||
}
|
||||
|
||||
applySnapshot(proofsStore, walletSnapshot.proofsStore)
|
||||
applySnapshot(mintsStore, walletSnapshot.mintsStore)
|
||||
applySnapshot(contactsStore, walletSnapshot.contactsStore)
|
||||
|
||||
// log.trace('After import', {rootStore})
|
||||
// log.trace('After import', {rootStore})
|
||||
const rootStore = rootStoreInstance
|
||||
log.trace('After import and mint keys hydration', {mintsStore})
|
||||
|
||||
// import proofs into the db
|
||||
if(proofsStore.proofsCount > 0) {
|
||||
@@ -270,7 +289,11 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
|
||||
mnemonic
|
||||
}
|
||||
|
||||
keys.SEED = seed
|
||||
keys.SEED = seed
|
||||
|
||||
// save keys as we need them next for publishing the recovered profile to relays
|
||||
await KeyChain.saveWalletKeys(keys)
|
||||
walletStore.cleanCachedWalletKeys()
|
||||
|
||||
if(isNewProfileNeeded) {
|
||||
|
||||
@@ -290,10 +313,7 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
|
||||
)
|
||||
}
|
||||
|
||||
// save keys after successful profile creation / recovery
|
||||
await KeyChain.saveWalletKeys(keys)
|
||||
|
||||
walletStore.cleanCachedWalletKeys()
|
||||
|
||||
|
||||
userSettingsStore.setIsOnboarded(true)
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { useStores } from '../models'
|
||||
import { translate } from '../i18n'
|
||||
import { MintUnit } from '../services/wallet/currency'
|
||||
import { Mint } from '../models/Mint'
|
||||
import { CashuUtils } from '../services/cashu/cashuUtils'
|
||||
|
||||
const hasAndroidCameraPermission = async () => {
|
||||
const cameraPermission = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA)
|
||||
@@ -202,6 +203,26 @@ export const ScanScreen: FC<WalletStackScreenProps<'Scan'>> = function ScanScree
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const maybeCashuPaymentRequest = CashuUtils.findEncodedCashuPaymentRequest(incoming)
|
||||
|
||||
if(maybeCashuPaymentRequest) {
|
||||
try {
|
||||
log.trace('Found Cashu Payment request instead of an invoice', maybeCashuPaymentRequest, 'onIncomingData')
|
||||
const encodedPr = CashuUtils.extractEncodedCashuPaymentRequest(maybeCashuPaymentRequest)
|
||||
|
||||
if(encodedPr) {
|
||||
await IncomingParser.navigateWithIncomingData({
|
||||
type: IncomingDataType.CASHU_PAYMENT_REQUEST,
|
||||
encoded: encodedPr
|
||||
}, navigation, unit, mint && mint.mintUrl)
|
||||
}
|
||||
return
|
||||
} catch (e3: any) {
|
||||
handleError(e3)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
e.params = incoming
|
||||
handleError(e)
|
||||
|
||||
@@ -510,7 +510,11 @@ export const SeedRecoveryScreen: FC<AppStackScreenProps<'SeedRecovery'>> = obser
|
||||
mnemonic
|
||||
}
|
||||
|
||||
keys.SEED = seed
|
||||
keys.SEED = seed
|
||||
|
||||
// save keys as we need them next for publishing the recovered profile to relays
|
||||
await KeyChain.saveWalletKeys(keys)
|
||||
walletStore.cleanCachedWalletKeys()
|
||||
|
||||
if(isNewProfileNeeded) {
|
||||
|
||||
@@ -530,11 +534,6 @@ export const SeedRecoveryScreen: FC<AppStackScreenProps<'SeedRecovery'>> = obser
|
||||
)
|
||||
}
|
||||
|
||||
// save keys after successful profile creation / recovery
|
||||
await KeyChain.saveWalletKeys(keys)
|
||||
|
||||
walletStore.cleanCachedWalletKeys()
|
||||
|
||||
userSettingsStore.setIsOnboarded(true)
|
||||
|
||||
if(!mintsStore.mintExists(MINIBITS_MINT_URL)) {
|
||||
|
||||
@@ -124,7 +124,7 @@ export const WalletScreen: FC<WalletScreenProps> = observer(
|
||||
setUpdateSize(`${round(update.packageSize * 0.000001, 2)}MB`)
|
||||
setIsUpdateAvailable(true)
|
||||
toggleUpdateModal()
|
||||
log.info('OTA Update available', update, 'checkForUpdate')
|
||||
log.trace('OTA Update available', update, 'checkForUpdate')
|
||||
}
|
||||
} catch (e: any) {
|
||||
return false // silent
|
||||
|
||||
@@ -166,7 +166,7 @@ const saveWalletKeys = async function (
|
||||
return keys
|
||||
}
|
||||
|
||||
log.warn('[getWalletKeys]', 'Did not find existing wallet keys in the KeyChain')
|
||||
log.debug('[getWalletKeys]', 'Did not find existing wallet keys in the KeyChain')
|
||||
return undefined
|
||||
} catch (e: any) {
|
||||
throw new AppError(Err.KEYCHAIN_ERROR, e.message, e)
|
||||
|
||||
@@ -14,7 +14,7 @@ import { NwcRequest, nwcPngUrl } from '../models/NwcStore';
|
||||
import { HANDLE_NWC_REQUEST_TASK, WalletTask, WalletTaskResult } from './walletService'
|
||||
import { SyncQueue } from './syncQueueService'
|
||||
import { delay } from '../utils/delay'
|
||||
import TaskQueue from 'taskon'
|
||||
import TaskQueue, { Task, TaskId, TaskStatus } from 'taskon'
|
||||
|
||||
export type NotifyReceiveToLnurlData = {
|
||||
type: 'NotifyReceiveToLnurlData',
|
||||
@@ -50,6 +50,28 @@ const getNwcQueue = function () {
|
||||
}
|
||||
|
||||
|
||||
const addNwcQueueTask = function (taskId: TaskId, task: Promise<any> | any) {
|
||||
const queue = getNwcQueue()
|
||||
|
||||
log.info(`Adding new nwcQueue task ${taskId} to the queue`)
|
||||
|
||||
queue
|
||||
.addTask(
|
||||
task,
|
||||
taskId, _handleNwcQueueTaskStatusChange)
|
||||
.then((result: any) => {
|
||||
log.info(`nwcQueue task ${taskId} completed.`)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const _handleNwcQueueTaskStatusChange = (status: TaskStatus) => {
|
||||
log.trace(
|
||||
`[_handleNwcQueueTaskStatusChange] The status of task changed to ${status}`,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const DEFAULT_CHANNEL_ID = 'default'
|
||||
const DEFAULT_CHANNEL_NAME = 'Minibits notifications'
|
||||
|
||||
@@ -64,7 +86,7 @@ export const TEST_CHANNEL_NAME = 'Minibits test tasks'
|
||||
|
||||
const initNotifications = async () => {
|
||||
let enabled = await areNotificationsEnabled()
|
||||
log.trace(`[initNotifications] Push notifications are ${enabled ? 'enabled' : 'disabled'}.`)
|
||||
log.debug(`[initNotifications] Push notifications are ${enabled ? 'enabled' : 'disabled'}.`)
|
||||
|
||||
if(!enabled) return
|
||||
|
||||
@@ -143,14 +165,12 @@ const onForegroundNotification = async function(remoteMessage: FirebaseMessaging
|
||||
// Process NWC request notified by FCM message by dedicated queue to avoid race condition
|
||||
// when starting foreground service
|
||||
if(remoteData.type === 'NotifyNwcRequestData') {
|
||||
const nwcQueue = getNwcQueue()
|
||||
nwcQueue
|
||||
.addTask(async () => {
|
||||
await _nwcRequestHandler(remoteData)
|
||||
})
|
||||
.then((result) => {
|
||||
log.trace('nwcQueue task completed.')
|
||||
})
|
||||
const now = new Date().getTime()
|
||||
|
||||
addNwcQueueTask(
|
||||
`_nwcRequestHandler-${now}`,
|
||||
async () => await _nwcRequestHandler(remoteData)
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -177,14 +197,12 @@ const onBackgroundNotification = async function(remoteMessage: FirebaseMessaging
|
||||
// Process NWC request notified by FCM message by dedicated queue to avoid race condition
|
||||
// when starting foreground service
|
||||
if(remoteData.type === 'NotifyNwcRequestData') {
|
||||
const nwcQueue = getNwcQueue()
|
||||
nwcQueue
|
||||
.addTask(async () => {
|
||||
await _nwcRequestHandler(remoteData)
|
||||
})
|
||||
.then((result) => {
|
||||
log.trace('nwcQueue task completed.')
|
||||
})
|
||||
const now = new Date().getTime()
|
||||
|
||||
addNwcQueueTask(
|
||||
`_nwcRequestHandler-${now}`,
|
||||
async () => await _nwcRequestHandler(remoteData)
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ export const sendFromMintSync = async function (
|
||||
amountWithFees,
|
||||
returnedAmount,
|
||||
transactionId
|
||||
})
|
||||
})
|
||||
|
||||
const sendResult = await walletStore.send(
|
||||
mintUrl,
|
||||
@@ -420,7 +420,13 @@ export const sendFromMintSync = async function (
|
||||
// try to clean spent proofs if that was the swap error cause
|
||||
if (e.params && e.params.message && e.params.message.includes('Token already spent')) {
|
||||
|
||||
log.error('[sendFromMintSync] Going to clean spent proofs from pending', {transactionId})
|
||||
log.error('[sendFromMintSync] Going to clean spent proofs from proofsToSendFrom and from pending', {transactionId})
|
||||
|
||||
await WalletTask.syncStateWithMintTask({
|
||||
proofsToSync: proofsToSendFrom,
|
||||
mintUrl,
|
||||
isPending: true
|
||||
})
|
||||
|
||||
await WalletTask.syncStateWithMintTask({
|
||||
proofsToSync: proofsStore.getByMint(mintUrl, {isPending: true, unit}),
|
||||
|
||||
Reference in New Issue
Block a user