aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-01-13 01:45:33 +0100
committerFlorian Dold <florian@dold.me>2023-01-13 01:45:33 +0100
commita3f9e8680501a3090d88220bf5a09681604c4471 (patch)
tree34e158d280a033f7d958086b7f3118c41ceaa3a3
parent8309f803ab3e0bcf56617697b7cf079f996bc1d0 (diff)
downloadwallet-core-a3f9e8680501a3090d88220bf5a09681604c4471.tar.xz
wallet-core: compute full peer push payment fees
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer.ts78
1 files changed, 75 insertions, 3 deletions
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts
index 68b8eb741..8dc468ad9 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -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