wallet-core: compute full peer push payment fees

This commit is contained in:
Florian Dold 2023-01-13 01:45:33 +01:00
parent 8309f803ab
commit a3f9e86805
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B

View File

@ -70,6 +70,7 @@ import {
} from "@gnu-taler/taler-util";
import { SpendCoinDetails } from "../crypto/cryptoImplementation.js";
import {
DenominationRecord,
OperationStatus,
PeerPullPaymentIncomingStatus,
PeerPushPaymentCoinSelection,
@ -97,6 +98,7 @@ import {
} from "../util/retries.js";
import { getPeerPaymentBalanceDetailsInTx } from "./balance.js";
import { updateExchangeFromUrl } from "./exchanges.js";
import { getTotalRefreshCost } from "./refresh.js";
import { internalCreateWithdrawalGroup } from "./withdraw.js";
const logger = new Logger("operations/peer-to-peer.ts");
@ -329,13 +331,83 @@ export async function selectPeerCoins(
return { type: "failure", insufficientBalanceDetails: errDetails };
}
export async function getTotalPeerPaymentCost(
ws: InternalWalletState,
pcs: PeerCoinSelectionDetails,
): Promise<AmountJson> {
return ws.db
.mktx((x) => [x.coins, x.denominations])
.runReadOnly(async (tx) => {
const costs: AmountJson[] = [];
for (let i = 0; i < pcs.coins.length; i++) {
const coin = await tx.coins.get(pcs.coins[i].coinPub);
if (!coin) {
throw Error("can't calculate payment cost, coin not found");
}
const denom = await tx.denominations.get([
coin.exchangeBaseUrl,
coin.denomPubHash,
]);
if (!denom) {
throw Error(
"can't calculate payment cost, denomination for coin not found",
);
}
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
.iter(coin.exchangeBaseUrl)
.filter((x) =>
Amounts.isSameCurrency(
DenominationRecord.getValue(x),
pcs.coins[i].contribution,
),
);
const amountLeft = Amounts.sub(
DenominationRecord.getValue(denom),
pcs.coins[i].contribution,
).amount;
const refreshCost = getTotalRefreshCost(
allDenoms,
DenominationRecord.toDenomInfo(denom),
amountLeft,
);
costs.push(Amounts.parseOrThrow(pcs.coins[i].contribution));
costs.push(refreshCost);
}
const zero = Amounts.zeroOfAmount(pcs.coins[0].contribution);
return Amounts.sum([zero, ...costs]).amount;
});
}
export async function preparePeerPushPayment(
ws: InternalWalletState,
req: PreparePeerPushPaymentRequest,
): Promise<PreparePeerPushPaymentResponse> {
// FIXME: look up for the exchange and calculate fee
const instructedAmount = Amounts.parseOrThrow(req.amount);
const coinSelRes: SelectPeerCoinsResult = await ws.db
.mktx((x) => [
x.exchanges,
x.contractTerms,
x.coins,
x.coinAvailability,
x.denominations,
x.refreshGroups,
x.peerPushPaymentInitiations,
])
.runReadWrite(async (tx) => {
const selRes = await selectPeerCoins(ws, tx, instructedAmount);
return selRes;
});
if (coinSelRes.type === "failure") {
throw TalerError.fromDetail(
TalerErrorCode.WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE,
{
insufficientBalanceDetails: coinSelRes.insufficientBalanceDetails,
},
);
}
const totalAmount = await getTotalPeerPaymentCost(ws, coinSelRes.result);
return {
amountEffective: req.amount,
amountEffective: Amounts.stringify(totalAmount),
amountRaw: req.amount,
};
}
@ -954,7 +1026,7 @@ export async function processPeerPullInitiation(
return {
type: OperationAttemptResultType.Finished,
result: undefined,
}
};
}
const mergeReserve = await ws.db