diff --git a/src/models/ProofsStore.ts b/src/models/ProofsStore.ts index 6eb4bfe9..0431eb82 100644 --- a/src/models/ProofsStore.ts +++ b/src/models/ProofsStore.ts @@ -5,6 +5,7 @@ import { flow, isAlive, } from 'mobx-state-tree' + import { Amount } from '@cashu/cashu-ts' import { withSetPropAction } from './helpers/withSetPropAction' import { ProofModel, Proof, ProofRecord, ProofState } from './Proof' import { TransactionData, TransactionStatus } from './Transaction' @@ -588,7 +589,7 @@ import { } else { const node = ProofModel.create({ ...proof, - amount: Number(proof.amount), + amount: Amount.from(proof.amount as any).toNumber(), mintUrl: commitMintUrl, tId: group.tId, unit: reservation.unit, diff --git a/src/screens/NfcPayScreen.tsx b/src/screens/NfcPayScreen.tsx index c3229c48..60096860 100644 --- a/src/screens/NfcPayScreen.tsx +++ b/src/screens/NfcPayScreen.tsx @@ -596,7 +596,7 @@ export const NfcPayScreen = observer(function NfcPayScreen({ route }: Props) { log.trace('[handlePaymentRequest] decoded Cashu payment request', { pr }) // Validate basics - if (!pr.amount || Number(pr.amount) <= 0) { + if (!pr.amount || pr.amount.toNumber() <= 0) { throw new AppError(Err.VALIDATION_ERROR, 'Payment request has no valid amount') } @@ -616,7 +616,7 @@ export const NfcPayScreen = observer(function NfcPayScreen({ route }: Props) { // setEncodedCashuPaymentRequest(encoded) if (pr.description) setMemo(pr.description) - const requiredAmount = Number(pr.amount) + const requiredAmount = pr.amount.toNumber() const eligibleBalances = await getEligibleMintBalancesForCashu(pr, requiredAmount, unit) if (eligibleBalances.length === 0) { diff --git a/src/screens/SendScreen.tsx b/src/screens/SendScreen.tsx index 5c1ed544..bc833e0d 100644 --- a/src/screens/SendScreen.tsx +++ b/src/screens/SendScreen.tsx @@ -625,7 +625,7 @@ export const SendScreen = observer(function SendScreen({ route }: Props) { setIsCashuPrWithDesc(true) } - const prAmount = pr.amount ? Number(pr.amount) : undefined + const prAmount = pr.amount ? pr.amount.toNumber() : undefined if (prAmount) { setAmountToSend(`${numbro(prAmount / getCurrency(unitRef.current).precision).format({ diff --git a/src/services/cashu/cashuUtils.ts b/src/services/cashu/cashuUtils.ts index d3c6d227..c2fcd09e 100644 --- a/src/services/cashu/cashuUtils.ts +++ b/src/services/cashu/cashuUtils.ts @@ -38,11 +38,20 @@ const isObj = function(v: unknown): v is object { return typeof v === 'object' } +/** + * An amount as a number. cashu-ts (4.x) types proof, token and payment-request + * amounts as `Amount` objects, while our own models hold plain numbers; `Number()` + * on an `Amount` is deprecated and throws in cashu-ts v5. + */ +const toNumberAmount = function(amount: number | Amount | bigint | string): number { + return typeof amount === 'number' ? amount : Amount.from(amount).toNumber() +} + /** * Sum the amounts of an array of proofs */ const sumProofs = function(proofs: CashuProof[]): number { - return proofs.reduce((acc: number, proof: CashuProof) => acc + Number(proof.amount), 0) + return proofs.reduce((acc: number, proof: CashuProof) => acc + toNumberAmount(proof.amount as any), 0) } const CASHU_URI_PREFIXES = [ @@ -839,6 +848,7 @@ export const CashuUtils = { extractEncodedCashuPaymentRequest, getProofsAmount, getMintsFromToken, + toNumberAmount, findExactMatch, findMinExcess, getProofsToSend, diff --git a/src/services/db/reservationsRepo.ts b/src/services/db/reservationsRepo.ts index e04aac92..94941f3f 100644 --- a/src/services/db/reservationsRepo.ts +++ b/src/services/db/reservationsRepo.ts @@ -1,4 +1,5 @@ import {isAlive} from 'mobx-state-tree' +import {Amount} from '@cashu/cashu-ts' import {Proof, ProofState} from '../../models/Proof' import {CashuProof} from '../cashu/cashuUtils' import {TransactionStatus} from '../../models/Transaction' @@ -225,7 +226,7 @@ export const commitReservation = function ( // binding can't bind non-primitive objects to an INTEGER column and // would silently drop the row, leaving the proof in MST but absent // from the database (lost on the next restart). - const amount = typeof proof.amount === 'number' ? proof.amount : Number(proof.amount) + const amount = typeof proof.amount === 'number' ? proof.amount : Amount.from(proof.amount as any).toNumber() batch.push([ `INSERT OR REPLACE INTO proofs (id, amount, secret, C, dleq_r, dleq_s, dleq_e, unit, tId, mintUrl, state, updatedAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, diff --git a/src/services/wallet/operations/cashuPaymentRequestApi.ts b/src/services/wallet/operations/cashuPaymentRequestApi.ts index b1990f28..7597925a 100644 --- a/src/services/wallet/operations/cashuPaymentRequestApi.ts +++ b/src/services/wallet/operations/cashuPaymentRequestApi.ts @@ -381,7 +381,7 @@ async function finalize( transactionId, ) - const receivedAmount = receivedProofs.reduce((acc, p) => acc + Number(p.amount), 0) + const receivedAmount = CashuUtils.getProofsAmount(receivedProofs) const outputToken = getEncodedToken({ mint: mintUrl, proofs: normalizeProofAmounts(receivedProofs), diff --git a/src/services/wallet/operations/nostrOperations.ts b/src/services/wallet/operations/nostrOperations.ts index 9b1dc908..c322c96f 100644 --- a/src/services/wallet/operations/nostrOperations.ts +++ b/src/services/wallet/operations/nostrOperations.ts @@ -140,7 +140,7 @@ const handleClaimTask = async function (params: { const result: TransactionTaskResult = await receiveTask( decodedToken, - Number(tokenInfo.amount), + tokenInfo.amount.toNumber(), tokenInfo.memo || 'Received to Lightning address', encodedToken, ) @@ -402,7 +402,7 @@ const handleReceivedEventTask = async function (encryptedEvent: NostrEvent): Pro if (incoming.type === IncomingDataType.CASHU) { const tokenInfo = getTokenMetadata(incoming.encoded) - const amountToReceive = Number(tokenInfo.amount) + const amountToReceive = tokenInfo.amount.toNumber() const memo = tokenInfo.memo || 'Received over Nostr' const {unit, mint: mintUrl} = tokenInfo diff --git a/src/services/wallet/operations/onchainTopupOperationApi.ts b/src/services/wallet/operations/onchainTopupOperationApi.ts index 351a3e34..6afedc8c 100644 --- a/src/services/wallet/operations/onchainTopupOperationApi.ts +++ b/src/services/wallet/operations/onchainTopupOperationApi.ts @@ -70,7 +70,7 @@ import { NUT20_RECOVERY_GAP_LIMIT, } from '../../cashu/nut20' import {capMintAmount, mintableAmount} from './onchainAmounts' -import {CashuProof} from '../../cashu/cashuUtils' +import {CashuProof, CashuUtils} from '../../cashu/cashuUtils' import {MintUnit} from '../currency' import {WalletUtils} from '../utils' import {sendTopupNotification} from '../notifications' @@ -548,7 +548,7 @@ async function _mintAvailable( }) } - const mintedAmount = proofs.reduce((acc, p) => acc + Number(p.amount), 0) + const mintedAmount = CashuUtils.getProofsAmount(proofs) const currentSpendable = proofsStore.getUnitBalance(unit)?.unitBalance ?? 0 const balanceAfter = currentSpendable + mintedAmount diff --git a/src/services/wallet/operations/receiveOperationApi.ts b/src/services/wallet/operations/receiveOperationApi.ts index 6feca224..b3d91400 100644 --- a/src/services/wallet/operations/receiveOperationApi.ts +++ b/src/services/wallet/operations/receiveOperationApi.ts @@ -318,7 +318,7 @@ async function execute(prepared: PreparedReceiveData): Promise acc + Number(p.amount), 0) + const receivedAmount = CashuUtils.getProofsAmount(proofs) const outputToken = getEncodedToken({ mint: prepared.mintUrl, proofs: normalizeProofAmounts(proofs), diff --git a/src/services/wallet/operations/topupOperationApi.ts b/src/services/wallet/operations/topupOperationApi.ts index cc289a61..15c1253d 100644 --- a/src/services/wallet/operations/topupOperationApi.ts +++ b/src/services/wallet/operations/topupOperationApi.ts @@ -56,7 +56,7 @@ import { isPrepared, isReverted, } from '../../../models/TransactionStates' -import {CashuProof} from '../../cashu/cashuUtils' +import {CashuProof, CashuUtils} from '../../cashu/cashuUtils' import {LightningUtils} from '../../lightning/lightningUtils' import {MintUnit, formatCurrency, getCurrency} from '../currency' import {NostrEvent} from '../../nostrService' @@ -533,7 +533,7 @@ async function _finalizePaid(tx: Transaction): Promise { }) const currentSpendable = proofsStore.getUnitBalance(unit)?.unitBalance ?? 0 - const proofsAmount = proofs.reduce((acc, p) => acc + Number(p.amount), 0) + const proofsAmount = CashuUtils.getProofsAmount(proofs) const balanceAfter = currentSpendable + proofsAmount const txData = _parseData(tx) diff --git a/src/services/wallet/revertTask.ts b/src/services/wallet/revertTask.ts index 282567ab..11652111 100644 --- a/src/services/wallet/revertTask.ts +++ b/src/services/wallet/revertTask.ts @@ -10,7 +10,7 @@ import { TransactionTaskResult } from '../walletService' import { ProofReservation } from './proofReservation' import { WalletUtils } from './utils' import { MintUnit } from './currency' -import { Token, getEncodedToken, normalizeProofAmounts } from '@cashu/cashu-ts' +import { Token, getEncodedToken, normalizeProofAmounts, sumProofs } from '@cashu/cashu-ts' const { mintsStore, @@ -99,7 +99,7 @@ try { // simulated: the original pending proofs were PENDING (contribute 0 to // UNSPENT pool); moving them to SPENT changes nothing. The new fresh // proofs added as UNSPENT raise the spendable balance. - const receivedAmount = receivedProofs.reduce((sum, p) => sum + Number(p.amount), 0) + const receivedAmount = sumProofs(receivedProofs).toNumber() const currentSpendable = proofsStore.getUnitBalance(unit)?.unitBalance ?? 0 const balanceAfter = currentSpendable + receivedAmount