mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-10-05 19:28:26 +00:00
Implement fees for swap (send)
This commit is contained in:
+95
-43
@@ -1,13 +1,14 @@
|
||||
import {cast, flow, Instance, SnapshotIn, SnapshotOut, types} from 'mobx-state-tree'
|
||||
import {withSetPropAction} from './helpers/withSetPropAction'
|
||||
import type {GetInfoResponse, MintKeys, MintKeyset} from '@cashu/cashu-ts'
|
||||
import type {CashuWallet, GetInfoResponse, MintKeys, MintKeyset} from '@cashu/cashu-ts'
|
||||
import {colors, getRandomIconColor} from '../theme'
|
||||
import { log, MintClient } from '../services'
|
||||
|
||||
import AppError, { Err } from '../utils/AppError'
|
||||
import { MintUnit } from '../services/wallet/currency'
|
||||
import { MintUnit, MintUnits } from '../services/wallet/currency'
|
||||
import { getRootStore } from './helpers/getRootStore'
|
||||
import { generateId } from '../utils/utils'
|
||||
import { Proof } from './Proof'
|
||||
|
||||
// used as a helper type across app
|
||||
/* export type Balance = {
|
||||
@@ -42,7 +43,7 @@ export enum MintStatus {
|
||||
export type MintProofsCounter = {
|
||||
keyset: string
|
||||
counter: number
|
||||
unit: MintUnit
|
||||
unit: MintUnit
|
||||
input_fee_ppk: number
|
||||
inFlightFrom?: number // starting counter index for pending split request sent to mint (for recovery from failure to receive proofs)
|
||||
inFlightTo?: number // last counter index for pending split request sent to mint
|
||||
@@ -94,37 +95,43 @@ export const MintModel = types
|
||||
|
||||
self.units = cast(self.units)
|
||||
},
|
||||
getProofsCounter(keysetId: string) {
|
||||
const counter = self.proofsCounters.find(c => c.keyset === keysetId)
|
||||
return counter
|
||||
},
|
||||
}))
|
||||
.actions(self => ({
|
||||
getOrCreateProofsCounter(keysetId: string, unit?: MintUnit, input_fee_ppk?: number) {
|
||||
log.trace('[getOrCreateProofsCounter]', keysetId, unit)
|
||||
const counter = self.proofsCounters.find(c => c.keyset === keysetId)
|
||||
|
||||
if(!counter) {
|
||||
if (!unit) {
|
||||
throw new AppError(Err.VALIDATION_ERROR, 'Can not create proofs counter: missing unit')
|
||||
}
|
||||
|
||||
const newCounter = {
|
||||
keyset: keysetId,
|
||||
unit,
|
||||
counter: 0,
|
||||
input_fee_ppk: input_fee_ppk || 0,
|
||||
}
|
||||
|
||||
self.proofsCounters.push(newCounter)
|
||||
self.addUnit(unit)
|
||||
const instance = self.proofsCounters.find(c => c.keyset === keysetId) as MintProofsCounter
|
||||
|
||||
log.trace('[getOrCreateProofsCounter] new', {newCounter: instance})
|
||||
return instance
|
||||
}
|
||||
|
||||
if(unit && counter.unit !== unit) {
|
||||
throw new AppError(Err.VALIDATION_ERROR, 'Mismatch of proofsCounter keyset and passed unit', {counter, unit})
|
||||
.actions(self => ({
|
||||
createProofsCounter(keyset: MintKeyset) {
|
||||
// Do not add unit the wallet does not have configured
|
||||
if (!MintUnits.includes(keyset.unit as MintUnit)) {
|
||||
throw new AppError(Err.VALIDATION_ERROR, `Unsupported unit provided by the mint: ${keyset.unit}`)
|
||||
}
|
||||
|
||||
return counter as MintProofsCounter
|
||||
const existing = self.getProofsCounter(keyset.id)
|
||||
|
||||
if(existing) { // update fees if they can change (?)
|
||||
if (existing.unit !== keyset.unit) {
|
||||
throw new AppError(Err.VALIDATION_ERROR, `Keyset unit mismatch, got ${keyset.unit}, expected ${existing.unit}`)
|
||||
}
|
||||
|
||||
existing.input_fee_ppk = keyset.input_fee_ppk || 0
|
||||
self.proofsCounters = cast(self.proofsCounters)
|
||||
return existing
|
||||
}
|
||||
|
||||
const newCounter: MintProofsCounter = {
|
||||
keyset: keyset.id,
|
||||
unit: keyset.unit as MintUnit,
|
||||
input_fee_ppk: keyset.input_fee_ppk || 0,
|
||||
counter: 0,
|
||||
}
|
||||
|
||||
self.proofsCounters.push(newCounter)
|
||||
self.addUnit(keyset.unit as MintUnit)
|
||||
const instance = self.proofsCounters.find(c => c.keyset === keyset.id) as MintProofsCounter
|
||||
|
||||
log.trace('[ceateProofsCounter]', {newCounter: instance})
|
||||
return instance
|
||||
},
|
||||
findInFlightProofsCounter() {
|
||||
const counter = self.proofsCounters.find(c => c.inFlightFrom && c.inFlightTo && c.inFlightTid)
|
||||
@@ -144,13 +151,31 @@ export const MintModel = types
|
||||
},
|
||||
}))
|
||||
.actions(self => ({
|
||||
getProofsCounterByUnit: flow(function* getProofsCounterByUnit(unit: MintUnit) {
|
||||
// Retrieve current keys for this unit from new or existing cashu-ts wallet instance
|
||||
const keys: MintKeys = (yield MintClient.getWallet(self.mintUrl, unit)).keys
|
||||
getProofsCounterByUnit: flow(function* getProofsCounterByUnit(unit: MintUnit) {
|
||||
try {
|
||||
// Refresh current keys for this unit from new or existing in-memory wallet instance
|
||||
const wallet: CashuWallet = yield MintClient.getWallet(self.mintUrl, unit)
|
||||
const keyset = wallet.keyset
|
||||
|
||||
// Get or create new proofs counter for this keyset
|
||||
const counter = self.getOrCreateProofsCounter(keys.id, unit)
|
||||
return counter
|
||||
// Get or create new proofs counter for this keyset
|
||||
const counter = self.getProofsCounter(keyset.id)
|
||||
|
||||
if(!counter) {
|
||||
return self.createProofsCounter(keyset)
|
||||
}
|
||||
|
||||
return counter
|
||||
} catch(e: any) {
|
||||
log.warn('[getProofsCounterByUnit] Could not refresh keyset, using mint proofsCounter for unit', {unit})
|
||||
|
||||
const proofsCounterInstance = self.proofsCounters.find(c => c.unit === unit)
|
||||
|
||||
if(!proofsCounterInstance) {
|
||||
throw new AppError(Err.NOTFOUND_ERROR, 'Could not get keyset to create new mint proofsCounter for unit', {unit})
|
||||
}
|
||||
|
||||
return proofsCounterInstance
|
||||
}
|
||||
}),
|
||||
setHostname() {
|
||||
try {
|
||||
@@ -207,8 +232,12 @@ export const MintModel = types
|
||||
setStatus(status: MintStatus) {
|
||||
self.status = status
|
||||
},
|
||||
setInFlight(keyset: string, options: {inFlightFrom: number, inFlightTo: number, inFlightTid: number}) {
|
||||
const counter = self.getOrCreateProofsCounter(keyset)
|
||||
setInFlight(keysetId: string, options: {inFlightFrom: number, inFlightTo: number, inFlightTid: number}) {
|
||||
const counter = self.getProofsCounter(keysetId)
|
||||
|
||||
if(!counter) {
|
||||
throw new AppError(Err.NOTFOUND_ERROR, 'Count not get mint proofsCounter for keysetId', {keysetId})
|
||||
}
|
||||
|
||||
counter.inFlightFrom = options.inFlightFrom
|
||||
counter.inFlightTo = options.inFlightTo
|
||||
@@ -235,16 +264,26 @@ export const MintModel = types
|
||||
|
||||
self.proofsCounters = cast(self.proofsCounters)
|
||||
},
|
||||
increaseProofsCounter(keyset: string, numberOfProofs: number) {
|
||||
const counter = self.getOrCreateProofsCounter(keyset)
|
||||
increaseProofsCounter(keysetId: string, numberOfProofs: number) {
|
||||
const counter = self.getProofsCounter(keysetId)
|
||||
|
||||
if(!counter) {
|
||||
throw new AppError(Err.NOTFOUND_ERROR, 'Count not get mint proofsCounter for keysetId', {keysetId})
|
||||
}
|
||||
|
||||
counter.counter += numberOfProofs
|
||||
log.trace('[increaseProofsCounter]', 'Increased proofsCounter', {numberOfProofs, counter})
|
||||
|
||||
// Make sure to cast the frozen array back to a mutable array
|
||||
self.proofsCounters = cast(self.proofsCounters)
|
||||
},
|
||||
decreaseProofsCounter(keyset: string, numberOfProofs: number) {
|
||||
const counter = self.getOrCreateProofsCounter(keyset)
|
||||
decreaseProofsCounter(keysetId: string, numberOfProofs: number) {
|
||||
const counter = self.getProofsCounter(keysetId)
|
||||
|
||||
if(!counter) {
|
||||
throw new AppError(Err.NOTFOUND_ERROR, 'Count not get mint proofsCounter for keysetId', {keysetId})
|
||||
}
|
||||
|
||||
counter.counter -= numberOfProofs
|
||||
Math.max(0, counter.counter)
|
||||
log.trace('[decreaseProofsCounter]', 'Decreased proofsCounter', {numberOfProofs, counter})
|
||||
@@ -259,6 +298,19 @@ export const MintModel = types
|
||||
|
||||
self.proofsCounters = cast(self.proofsCounters)
|
||||
},
|
||||
getFeesForProofs(proofs: Proof[]): number {
|
||||
// Find the corresponding MintProofsCounter for each proof and sum the input fees
|
||||
const totalInputFees = proofs.reduce((sum, proof) => {
|
||||
const counter = self.proofsCounters.find(pc => pc.keyset === proof.id)
|
||||
return counter ? sum + counter.input_fee_ppk : sum
|
||||
}, 0)
|
||||
|
||||
// Calculate the fees
|
||||
const fees = Math.max(Math.floor((totalInputFees + 999) / 1000), 0)
|
||||
|
||||
log.debug('*** [getFeesForProofs]', {fees})
|
||||
return fees
|
||||
}
|
||||
}))
|
||||
.views(self => ({
|
||||
get balances(): MintBalance | undefined {
|
||||
|
||||
+10
-14
@@ -62,20 +62,16 @@ import { MintUnit, MintUnits } from '../services/wallet/currency'
|
||||
mintInstance.setRandomColor()
|
||||
|
||||
for(const keyset of activeKeysets) {
|
||||
if(keyset.active === true) {
|
||||
// Do not add unit the wallet does not have configured
|
||||
if (!MintUnits.includes(keyset.unit as MintUnit)) {
|
||||
log.error(`Unsupported unit provided by the mint: ${keyset.unit}`)
|
||||
continue
|
||||
try {
|
||||
if(keyset.active === true) {
|
||||
mintInstance.createProofsCounter(keyset)
|
||||
}
|
||||
|
||||
mintInstance.addUnit(keyset.unit as MintUnit) // add supported units by mint
|
||||
mintInstance.getOrCreateProofsCounter(keyset.id, keyset.unit as MintUnit, keyset.input_fee_ppk || 0) // create proofsCounters
|
||||
} catch(e: any) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
yield mintInstance.setShortname()
|
||||
|
||||
yield mintInstance.setShortname()
|
||||
self.mints.push(mintInstance)
|
||||
}),
|
||||
updateMint: flow(function* updateMint(mintUrl: string) {
|
||||
@@ -86,13 +82,13 @@ import { MintUnit, MintUnits } from '../services/wallet/currency'
|
||||
throw new AppError(Err.VALIDATION_ERROR, 'Could not find mint to update', {mintUrl})
|
||||
}
|
||||
// refresh up to date mint keys
|
||||
const activeKeysets: MintKeyset[] = yield MintClient.getMintKeysets(mintUrl)
|
||||
const allKeysets: MintKeyset[] = yield MintClient.getMintKeysets(mintUrl)
|
||||
|
||||
if(!activeKeysets || activeKeysets.length === 0) {
|
||||
if(!allKeysets || allKeysets.length === 0) {
|
||||
throw new AppError(Err.VALIDATION_ERROR, 'Mint has no active keysets and is not operational', {mintUrl})
|
||||
}
|
||||
|
||||
for(const keyset of activeKeysets) {
|
||||
for(const keyset of allKeysets) {
|
||||
if(keyset.active === true) {
|
||||
// Do not add unit the wallet does not have configured
|
||||
if (!MintUnits.includes(keyset.unit as MintUnit)) {
|
||||
@@ -101,7 +97,7 @@ import { MintUnit, MintUnits } from '../services/wallet/currency'
|
||||
}
|
||||
|
||||
mintInstance.addUnit(keyset.unit as MintUnit) // add supported units by mint if not yet exist
|
||||
mintInstance.getOrCreateProofsCounter(keyset.id, keyset.unit as MintUnit, keyset.input_fee_ppk || 0) // create proofsCounters if not yet exist
|
||||
mintInstance.createProofsCounter(keyset) // create proofsCounters or update fees if exists
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-34
@@ -363,30 +363,19 @@ export const ProofsStoreModel = types
|
||||
|
||||
log.debug('[getMintBalanceWithMaxBalance]', {balances})
|
||||
|
||||
/*const maxBalance = balances.reduce((maxBalance, currentBalance) => {
|
||||
if(currentBalance.balances[unit] === undefined) {
|
||||
return maxBalance
|
||||
}
|
||||
|
||||
if (currentBalance.balances[unit] || 0 > maxBalance.balances[unit]!) {
|
||||
return currentBalance
|
||||
}
|
||||
return maxBalance
|
||||
})*/
|
||||
|
||||
let maxBalance = null;
|
||||
let maxAmount = -Infinity;
|
||||
let maxBalance = null;
|
||||
let maxAmount = -Infinity;
|
||||
|
||||
for (const balance of balances) {
|
||||
const amount = balance.balances[unit];
|
||||
if (amount !== undefined && amount > maxAmount) {
|
||||
maxAmount = amount;
|
||||
maxBalance = balance;
|
||||
}
|
||||
}
|
||||
for (const balance of balances) {
|
||||
const amount = balance.balances[unit];
|
||||
if (amount !== undefined && amount > maxAmount) {
|
||||
maxAmount = amount;
|
||||
maxBalance = balance;
|
||||
}
|
||||
}
|
||||
|
||||
log.debug('[getMintBalanceWithMaxBalance]', {maxBalance})
|
||||
return maxBalance;
|
||||
log.debug('[getMintBalanceWithMaxBalance]', {maxBalance})
|
||||
return maxBalance;
|
||||
},
|
||||
getUnitBalance: (unit: MintUnit) => {
|
||||
const balances = self.getBalances().unitBalances
|
||||
@@ -395,22 +384,12 @@ export const ProofsStoreModel = types
|
||||
.find((balance: UnitBalance) => balance.unit === unit)
|
||||
|
||||
return unitBalance
|
||||
},
|
||||
getProofsToSend: (amount: number, proofs: Proof[]) => {
|
||||
let proofsAmount = 0
|
||||
const proofSubset = proofs.filter(proof => {
|
||||
if (proofsAmount < amount) {
|
||||
proofsAmount += proof.amount
|
||||
return true
|
||||
}
|
||||
})
|
||||
return proofSubset
|
||||
},
|
||||
},
|
||||
getProofsSubset: (proofs: Proof[], proofsToRemove: Proof[]) => {
|
||||
return proofs.filter(proof => !proofsToRemove.includes(proof))
|
||||
},
|
||||
}))
|
||||
|
||||
|
||||
|
||||
export interface Proofs extends Instance<typeof ProofsStoreModel> {}
|
||||
export interface ProofsStoreSnapshot
|
||||
|
||||
@@ -193,7 +193,7 @@ const getProofsFromTokenEntries = (tokenEntries: TokenEntry[]) => {
|
||||
* @param tokens
|
||||
* @returns
|
||||
*/
|
||||
const getProofsToSend = function (amount: number, proofs: Array<Proof>) {
|
||||
/* const getProofsToSend = function (amount: number, proofs: Array<Proof>) {
|
||||
let proofsAmount = 0
|
||||
const proofSubset = proofs.filter(proof => {
|
||||
if (proofsAmount < amount) {
|
||||
@@ -202,7 +202,52 @@ const getProofsToSend = function (amount: number, proofs: Array<Proof>) {
|
||||
}
|
||||
})
|
||||
return proofSubset
|
||||
}
|
||||
} */
|
||||
|
||||
export const getProofsToSend = (amount: number, proofs: Proof[]) => {
|
||||
if (proofs.reduce((s, t) => (s += t.amount), 0) < amount) {
|
||||
// there are not enough proofs to pay the amount
|
||||
throw new AppError(Err.VALIDATION_ERROR, 'Not enough proofs to match requested amount', {amount})
|
||||
}
|
||||
|
||||
// sort proofs by amount ascending
|
||||
proofs = proofs.slice().sort((a, b) => a.amount - b.amount);
|
||||
// remember next bigger proof as a fallback
|
||||
const nextBigger = proofs.find((p) => p.amount > amount);
|
||||
|
||||
// go through smaller proofs until sum is bigger than amount
|
||||
const smallerProofs = proofs.filter((p) => p.amount <= amount);
|
||||
// sort by amount descending
|
||||
smallerProofs.sort((a, b) => b.amount - a.amount);
|
||||
|
||||
let selectedProofs: Proof[] = [];
|
||||
|
||||
if (smallerProofs.length == 0 && nextBigger) {
|
||||
// if there are no smaller proofs, take the next bigger proof as a fallback
|
||||
return [nextBigger];
|
||||
} else if (smallerProofs.length == 0 && !nextBigger) {
|
||||
// no proofs available
|
||||
return [];
|
||||
}
|
||||
|
||||
// recursively select the largest proof of smallerProofs, subtract the amount from the remainder
|
||||
// and call coinSelect again with the remainder and the rest of the smallerProofs (without the largest proof)
|
||||
let remainder = amount;
|
||||
selectedProofs = [smallerProofs[0]];
|
||||
remainder -= smallerProofs[0].amount;
|
||||
if (remainder > 0) {
|
||||
selectedProofs = selectedProofs.concat(getProofsToSend(remainder, smallerProofs.slice(1)));
|
||||
}
|
||||
let sum = selectedProofs.reduce((s, t) => (s += t.amount), 0);
|
||||
|
||||
// if sum of selectedProofs is smaller than amount, take next bigger proof instead as a fallback
|
||||
if (sum < amount && nextBigger) {
|
||||
selectedProofs = [nextBigger];
|
||||
}
|
||||
|
||||
log.trace("[getProofsToSend] ### selected amounts", "sum", selectedProofs.reduce((s, t) => (s += t.amount), 0), selectedProofs.map(p => p.amount));
|
||||
return selectedProofs
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,17 +144,23 @@ const getWallet = async function (
|
||||
mnemonicOrSeed: seed
|
||||
})
|
||||
|
||||
// make sure we have keys for wallet unit cached in wallet instance
|
||||
const keys = await newSeedWallet.getKeys(undefined, unit)
|
||||
try {
|
||||
// make sure we have keys for wallet unit cached in wallet instance
|
||||
const keys = await newSeedWallet.getKeys(undefined, unit)
|
||||
|
||||
if(!keys || keys.unit !== unit) {
|
||||
throw new AppError(Err.VALIDATION_ERROR, `This mint does not currently support unit ${unit}`)
|
||||
if(!keys || keys.unit !== unit) {
|
||||
throw new AppError(Err.VALIDATION_ERROR, `This mint does not currently support unit ${unit}`)
|
||||
}
|
||||
|
||||
_seedWallets.push(newSeedWallet)
|
||||
|
||||
log.trace('[getWallet]', 'Returning new cashuWallet instance with seed')
|
||||
return newSeedWallet
|
||||
} catch (e: any) {
|
||||
let message = 'Could not connect to the selected mint.'
|
||||
if (isOnionMint(mintUrl)) message += TorVPNSetupInstructions;
|
||||
throw new AppError(Err.NETWORK_ERROR, message, {message: e.message, caller: 'getWallet'})
|
||||
}
|
||||
|
||||
_seedWallets.push(newSeedWallet)
|
||||
|
||||
log.trace('[getWallet]', 'Returning new cashuWallet instance with seed')
|
||||
return newSeedWallet
|
||||
}
|
||||
|
||||
const wallet = _wallets.find(w => w.mint.mintUrl === mintUrl && w.unit === unit)
|
||||
|
||||
@@ -24,6 +24,7 @@ import { poller } from '../../utils/poller'
|
||||
import { WalletUtils } from './utils'
|
||||
import { getSnapshot, isStateTreeNode } from 'mobx-state-tree'
|
||||
import { MintUnit } from './currency'
|
||||
import { getProofsToSend } from '../../services/cashu/cashuUtils'
|
||||
|
||||
const {
|
||||
mintsStore,
|
||||
@@ -86,7 +87,7 @@ export const sendTask = async function (
|
||||
// Update transaction status
|
||||
transactionData.push({
|
||||
status: TransactionStatus.PREPARED,
|
||||
proofsToSend,
|
||||
//proofsToSend,
|
||||
createdAt: new Date(),
|
||||
})
|
||||
|
||||
@@ -191,7 +192,7 @@ export const sendFromMint = async function (
|
||||
) {
|
||||
const mintUrl = mintBalance.mintUrl
|
||||
const mintInstance = mintsStore.findByUrl(mintUrl)
|
||||
|
||||
|
||||
try {
|
||||
if (!mintInstance) {
|
||||
throw new AppError(
|
||||
@@ -228,11 +229,11 @@ export const sendFromMint = async function (
|
||||
|
||||
const selectedProofsAmount = CashuUtils.getProofsAmount(selectedProofs)
|
||||
|
||||
if(selectedProofsAmount > 0 && (amountToSend !== selectedProofsAmount)) { // failsafe for some unknown ecash selection UX error
|
||||
throw new AppError(Err.VALIDATION_ERROR, 'Requested amount to send does not equal sum of ecash denominations provided.')
|
||||
}
|
||||
if(selectedProofsAmount > 0) {
|
||||
if(amountToSend !== selectedProofsAmount) { // failsafe for some unknown ecash selection UX error
|
||||
throw new AppError(Err.VALIDATION_ERROR, 'Requested amount to send does not equal sum of ecash denominations provided.')
|
||||
}
|
||||
|
||||
if(selectedProofsAmount > 0) {
|
||||
for (const proof of selectedProofs) {
|
||||
proof.setTransactionId(transactionId) // update txId
|
||||
}
|
||||
@@ -250,32 +251,71 @@ export const sendFromMint = async function (
|
||||
// We return cleaned proofs to be encoded as a sendable token
|
||||
return cleanedProofsToSend
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* if we did not selected ecash but amount and we might need a split of ecash by the mint to match exact amount
|
||||
* if we did not selected ecash but amount and we might need a swap of ecash by the mint to match exact amount
|
||||
*/
|
||||
|
||||
const proofsToSendFrom = proofsStore.getProofsToSend(
|
||||
const proofsToSendFrom = getProofsToSend(
|
||||
amountToSend,
|
||||
proofsFromMint,
|
||||
)
|
||||
|
||||
const proofsToSendFromAmount = CashuUtils.getProofsAmount(proofsToSendFrom)
|
||||
let proofsToSendFromAmount = CashuUtils.getProofsAmount(proofsToSendFrom)
|
||||
|
||||
|
||||
// Increase the proofs counter before the mint call so that in case the response
|
||||
// is not received our recovery index counts for sigs the mint has already issued (prevents duplicate b_b bug)
|
||||
const amountPreferences = getDefaultAmountPreference(amountToSend)
|
||||
const returnedAmountPreferences = getDefaultAmountPreference(proofsToSendFromAmount - amountToSend)
|
||||
// swap will happen if we could not select proofs equal to amountToSend
|
||||
let returnedAmount = proofsToSendFromAmount - amountToSend
|
||||
let feesAmount: number = 0
|
||||
|
||||
if(returnedAmount > 0) {
|
||||
feesAmount = mintInstance.getFeesForProofs(proofsToSendFrom)
|
||||
// if we did not selected enough proofs to cover the fees we need some more
|
||||
if(feesAmount > returnedAmount) {
|
||||
const missingFeesAmount = feesAmount - returnedAmount
|
||||
const remainingProofs = proofsStore.getProofsSubset(proofsFromMint, proofsToSendFrom)
|
||||
const remainingProofsAmount = CashuUtils.getProofsAmount(remainingProofs)
|
||||
|
||||
log.warn('[sendFromMint]', 'Not enough proofs to cover feeAmount', {feesAmount, returnedAmount})
|
||||
|
||||
if(missingFeesAmount > remainingProofsAmount) {
|
||||
throw new AppError(
|
||||
Err.VALIDATION_ERROR,
|
||||
'There is not enough funds to send this payment with expected fees',
|
||||
{totalAmountFromMint, amountToSend, feesAmount},
|
||||
)
|
||||
}
|
||||
|
||||
const proofsToPayFees = getProofsToSend(
|
||||
missingFeesAmount,
|
||||
remainingProofs
|
||||
)
|
||||
|
||||
// add more proofs into inputs and recalculate amounts
|
||||
proofsToSendFrom.push(...proofsToPayFees)
|
||||
proofsToSendFromAmount = CashuUtils.getProofsAmount(proofsToSendFrom)
|
||||
returnedAmount = proofsToSendFromAmount - amountToSend
|
||||
}
|
||||
|
||||
// decrease requested returned outputs by fees so mint can charge them
|
||||
returnedAmount -= feesAmount
|
||||
}
|
||||
|
||||
// Inputs we are about to send
|
||||
const amountPreferences = getDefaultAmountPreference(amountToSend)
|
||||
// Outputs we are about to get back if swap occurs
|
||||
const returnedAmountPreferences = getDefaultAmountPreference(returnedAmount)
|
||||
|
||||
const countOfProofsToSend = CashuUtils.getAmountPreferencesCount(amountPreferences)
|
||||
const countOfReturnedProofs = CashuUtils.getAmountPreferencesCount(returnedAmountPreferences)
|
||||
const countOfInFlightProofs = countOfProofsToSend + countOfReturnedProofs
|
||||
|
||||
const countOfInFlightProofs = countOfProofsToSend + countOfReturnedProofs
|
||||
|
||||
log.trace('[sendFromMint]', 'amountPreferences', {amountPreferences, returnedAmountPreferences})
|
||||
log.trace('[sendFromMint]', 'countOfInFlightProofs', countOfInFlightProofs)
|
||||
|
||||
// temp increase the counter + acquire lock and set inFlight values
|
||||
// Increase the proofs counter before the mint call so that in case the response
|
||||
// is not received our recovery index counts for sigs the mint has already issued (prevents duplicate b_b bug)
|
||||
// + acquire lock and set inFlight values
|
||||
await WalletUtils.lockAndSetInFlight(mintInstance, unit, countOfInFlightProofs, transactionId)
|
||||
|
||||
// get locked counter values
|
||||
@@ -352,4 +392,5 @@ export const sendFromMint = async function (
|
||||
throw new AppError(Err.WALLET_ERROR, e.message, e.stack.slice(0, 200))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user