diff options
author | Florian Dold <florian@dold.me> | 2023-01-13 01:45:33 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2023-01-13 01:45:33 +0100 |
commit | a3f9e8680501a3090d88220bf5a09681604c4471 (patch) | |
tree | 34e158d280a033f7d958086b7f3118c41ceaa3a3 | |
parent | 8309f803ab3e0bcf56617697b7cf079f996bc1d0 (diff) |
wallet-core: compute full peer push payment fees
-rw-r--r-- | packages/taler-wallet-core/src/operations/pay-peer.ts | 78 |
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 |