Fix keysets mutation

This commit is contained in:
minibits-cash
2026-01-13 22:23:07 +01:00
parent 7502cdfd5a
commit 6d188a78f4
8 changed files with 73 additions and 53 deletions
@@ -447,7 +447,10 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
@@ -530,7 +533,10 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
+28 -14
View File
@@ -297,20 +297,30 @@ export const MintModel = types
}
},
setIsActive(freshKeyset: CashuMintKeyset) {
const keyset = self.keysets.find(k => k.id === freshKeyset.id)
const index = self.keysets.findIndex(k => k.id === freshKeyset.id)
if(keyset) {
keyset.active = freshKeyset.active
if(index !== -1) {
// Since keysets is a frozen array, we need to replace the entire keyset object
const updatedKeyset = {
...self.keysets[index],
active: freshKeyset.active
}
self.keysets[index] = updatedKeyset
self.keysets = cast(self.keysets)
}
}
},
setInputFeePpk(keysetId: string, inputFeePpk: number) {
const keyset = self.keysets.find(k => k.id === keysetId)
const index = self.keysets.findIndex(k => k.id === keysetId)
if(keyset) {
keyset.input_fee_ppk = inputFeePpk
if(index !== -1) {
// Since keysets is a frozen array, we need to replace the entire keyset object
const updatedKeyset = {
...self.keysets[index],
input_fee_ppk: inputFeePpk
}
self.keysets[index] = updatedKeyset
self.keysets = cast(self.keysets)
}
}
},
addKeys(keys: CashuMintKeys) {
const alreadyExists = self.keys.some(k => k.id === keys.id)
@@ -415,18 +425,22 @@ export const MintModel = types
const existing = self.keysets.find(k => k.id === keyset.id)
if(existing) {
if (existing.unit !== keyset.unit) {
if (existing.unit !== keyset.unit) {
throw new AppError(
Err.VALIDATION_ERROR,
Err.VALIDATION_ERROR,
`Keyset unit mismatch.`,
{caller: 'initKeyset', existingUnit: existing.unit, keysetUnit: keyset.unit}
)
)
}
if(keyset.input_fee_ppk && existing.input_fee_ppk !== keyset.input_fee_ppk) {
self.setInputFeePpk(existing.id, keyset.input_fee_ppk)
}
if(existing.active !== keyset.active) {
self.setIsActive(keyset)
}
return existing
}
@@ -479,16 +493,16 @@ export const MintModel = types
},
}))
.actions(self => ({
refreshKeysets(freshKeysets: CashuMintKeyset[]) {
refreshKeysets(freshKeysets: CashuMintKeyset[]) {
const mintsStore = getRootStore(self).mintsStore
const allKeysetIds = mintsStore.allKeysetIds
log.trace('[refreshKeysets]', {freshKeysets, allKeysetIds})
// add new keyset if not exists
// add new keyset if not exists
for (const keyset of freshKeysets) {
// initKeyset now handles active status updates internally
self.initKeyset(keyset, allKeysetIds)
self.setIsActive(keyset)
}
},
refreshKeys(freshKeys: CashuMintKeys[]) {
+2 -2
View File
@@ -182,8 +182,8 @@ export const MintsStoreModel = types
// refresh up to date mint keys
const newMint = new CashuMint(mintUrl)
// get fresh keysets
const keySetResult: MintAllKeysets = yield newMint.getKeySets()
const keysResult: MintActiveKeys = yield newMint.getKeys()
const keySetResult: GetKeysetsResponse = yield newMint.getKeySets()
const keysResult: GetKeysResponse = yield newMint.getKeys()
const {keysets} = keySetResult
const {keysets: keys} = keysResult
+30 -30
View File
@@ -28,7 +28,7 @@ import { InFlightRequest, Mint } from './Mint'
import { getRootStore } from './helpers/getRootStore'
import { Transaction } from './Transaction'
//refresh
/*
Not persisted, in-memory only model of the cashu-ts wallet instances and wallet keys persisted in the device secure store.
It is instantiated on first use so that wallet retrieves fresh mint keysets, then cached,
@@ -375,8 +375,8 @@ export const WalletStoreModel = types
const cashuMint: CashuMint = yield self.getMint(mintUrl)
try {
const {keysets} = yield cashuMint.getKeys() as Promise<GetKeysResponse> // all active keys
return keysets as MintKeys[]
const {keysets: keys} = yield cashuMint.getKeys() as Promise<GetKeysResponse> // all active keys
return keys as MintKeys[]
} catch (e: any) {
let message = 'Could not connect to the selected mint.'
if (isOnionMint(mintUrl)) message += TorVPNSetupInstructions;
@@ -1026,7 +1026,7 @@ export const WalletStoreModel = types
const currentCounter = mintInstance.getProofsCounterByKeysetId!(transaction.keysetId)
const meltCounterValue = currentCounter.getMeltCounterValue(transaction.id)
if(!meltCounterValue) {
if(!meltCounterValue || !meltCounterValue.meltPreview) {
throw new AppError(Err.VALIDATION_ERROR, 'Change already claimed - melt data not available for this transaction', {mintUrl, transactionId})
}
@@ -1078,32 +1078,32 @@ export const WalletStoreModel = types
}
) {
try {
const {indexFrom, indexTo, keysetId} = options
// need special wallet instance to pass seed and keysetId directly
const cashuMint = yield self.getMint(mintUrl)
const seedWallet = new CashuWallet(cashuMint, {
unit: 'sat', // just use default unit as we restore by keyset
keys: cashuMint.keys,
keysets: cashuMint.keysets,
keysetId,
bip39seed: seed
})
const count = Math.abs(indexTo - indexFrom)
const {proofs} = yield seedWallet.restore(
indexFrom,
count,
{keysetId}
)
log.info('[restore]', 'Number of recovered proofs', {proofs: proofs.length})
return {
proofs: proofs || [] as Proof[]
}
const {indexFrom, indexTo, keysetId} = options
// need special wallet instance to pass seed and keysetId directly
const cashuMint = yield self.getMint(mintUrl)
const seedWallet = new CashuWallet(cashuMint, {
unit: 'sat', // just use default unit as we restore by keyset
keys: cashuMint.keys,
keysets: cashuMint.keysets,
keysetId,
bip39seed: seed
})
const count = Math.abs(indexTo - indexFrom)
const {proofs} = yield seedWallet.restore(
indexFrom,
count,
{keysetId}
)
log.info('[restore]', 'Number of recovered proofs', {proofs: proofs.length})
return {
proofs: proofs || [] as Proof[]
}
} catch (e: any) {
throw new AppError(Err.MINT_ERROR, CashuUtils.isObj(e.message) ? JSON.stringify(e.message) : e.message, {mintUrl})
}
+1 -1
View File
@@ -34,7 +34,7 @@ import RNExitApp from 'react-native-exit-app'
import { TransactionStatus } from '../models/Transaction'
import { maxTransactionsInHistory } from '../models/TransactionsStore'
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
//
// refresh
type Props = StaticScreenProps<undefined>
+1 -1
View File
@@ -18,7 +18,7 @@ import { Platform } from "react-native"
import AppError, { Err } from "../utils/AppError"
const { userSettingsStore } = rootStoreInstance
// refresh
if (!__DEV__) {
Sentry.init({
+1 -1
View File
@@ -8,7 +8,7 @@ import { WalletProfileRecord } from "../models/WalletProfileStore"
import { CurrencyCode } from "./wallet/currency"
import { rootStoreInstance } from "../models"
import { AuthChallengeResponse, TokenPair, VerifyChallengeResponse } from "../models/AuthStore"
// refresh
//
type MinibitsRequestArgs = {
method: 'POST' | 'PUT' | 'DELETE' | 'GET'
+2 -2
View File
@@ -1680,8 +1680,8 @@ const handleInFlightByMintTask = async (mint: Mint): Promise<WalletTaskResult> =
tx.update({ outputToken })
}
if (quote.payment_preimage) {
tx.update({ proof: quote.payment_preimage })
if (meltQuoteCheck.payment_preimage) {
tx.update({ proof: meltQuoteCheck.payment_preimage })
}
const inputAmount = CashuUtils.getProofsAmount(inFlight.request.proofsToSend)