From 74dba9506dba104d918c5386e67146f71f07436c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 29 Mar 2023 15:14:02 -0300 Subject: show wire details when the deposit has been wired --- packages/taler-wallet-core/src/db.ts | 14 ++++ .../taler-wallet-core/src/operations/deposits.ts | 93 +++++++++++++++++++++- .../src/operations/transactions.ts | 2 + 3 files changed, 108 insertions(+), 1 deletion(-) (limited to 'packages/taler-wallet-core/src') diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index cd676b7ca..fb5ea025a 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -1671,6 +1671,20 @@ export interface DepositGroupRecord { operationStatus: OperationStatus; transactionPerCoin: TransactionStatus[]; + + trackingState?: { + [signature: string]: { + // Raw wire transfer identifier of the deposit. + wireTransferId: string; + // When was the wire transfer given to the bank. + timestampExecuted: TalerProtocolTimestamp; + // Total amount transfer for this wtid (including fees) + amountRaw: AmountString; + // Total amount received for this wtid (without fees) + amountEffective: AmountString; + exchangePub: string; + }; + }; } /** diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index 22283b7a8..c6cd4732c 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -53,12 +53,15 @@ import { TrackDepositGroupRequest, TrackDepositGroupResponse, TrackTransaction, + TrackTransactionWired, TransactionType, URL, + WireFee, } from "@gnu-taler/taler-util"; import { DenominationRecord, DepositGroupRecord, + ExchangeDetailsRecord, OperationStatus, TransactionStatus, } from "../db.js"; @@ -157,7 +160,6 @@ export async function processDepositGroup( const perm = depositPermissions[i]; let updatedDeposit: boolean | undefined = undefined; - let updatedTxStatus: TransactionStatus | undefined = undefined; if (!depositGroup.depositedPerCoin[i]) { const requestBody: ExchangeDepositRequest = { @@ -186,6 +188,17 @@ export async function processDepositGroup( updatedDeposit = true; } + let updatedTxStatus: TransactionStatus | undefined = undefined; + type ValueOf = T[keyof T]; + + let newWiredTransaction: + | { + id: string; + value: ValueOf>; + } + | undefined; + + let signature: string | undefined; if (depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired) { const track = await trackDepositPermission(ws, depositGroup, perm); @@ -207,6 +220,32 @@ export async function processDepositGroup( } } else if (track.type === "wired") { updatedTxStatus = TransactionStatus.Wired; + + const payto = parsePaytoUri(depositGroup.wire.payto_uri); + if (!payto) { + throw Error(`unparsable payto: ${depositGroup.wire.payto_uri}`); + } + + const fee = await getExchangeWireFee( + ws, + payto.targetType, + perm.exchange_url, + track.execution_time, + ); + const raw = Amounts.parseOrThrow(track.coin_contribution); + const wireFee = Amounts.parseOrThrow(fee.wireFee); + const effective = Amounts.sub(raw, wireFee).amount; + + newWiredTransaction = { + value: { + amountRaw: Amounts.stringify(raw), + amountEffective: Amounts.stringify(effective), + exchangePub: track.exchange_pub, + timestampExecuted: track.execution_time, + wireTransferId: track.wtid, + }, + id: track.exchange_sig, + }; } else { updatedTxStatus = TransactionStatus.Unknown; } @@ -226,6 +265,14 @@ export async function processDepositGroup( if (updatedTxStatus !== undefined) { dg.transactionPerCoin[i] = updatedTxStatus; } + if (newWiredTransaction) { + if (!dg.trackingState) { + dg.trackingState = {}; + } + + dg.trackingState[newWiredTransaction.id] = + newWiredTransaction.value; + } await tx.depositGroups.put(dg); }); } @@ -257,6 +304,50 @@ export async function processDepositGroup( return OperationAttemptResult.finishedEmpty(); } +async function getExchangeWireFee( + ws: InternalWalletState, + wireType: string, + baseUrl: string, + time: TalerProtocolTimestamp, +): Promise { + const exchangeDetails = await ws.db + .mktx((x) => [x.exchanges, x.exchangeDetails]) + .runReadOnly(async (tx) => { + const ex = await tx.exchanges.get(baseUrl); + if (!ex || !ex.detailsPointer) return undefined; + return await tx.exchangeDetails.indexes.byPointer.get([ + baseUrl, + ex.detailsPointer.currency, + ex.detailsPointer.masterPublicKey, + ]); + }); + + if (!exchangeDetails) { + throw Error(`exchange missing: ${baseUrl}`); + } + + const fees = exchangeDetails.wireInfo.feesForType[wireType]; + if (!fees || fees.length === 0) { + throw Error( + `exchange ${baseUrl} doesn't have fees for wire type ${wireType}`, + ); + } + const fee = fees.find((x) => { + return AbsoluteTime.isBetween( + AbsoluteTime.fromTimestamp(time), + AbsoluteTime.fromTimestamp(x.startStamp), + AbsoluteTime.fromTimestamp(x.endStamp), + ); + }); + if (!fee) { + throw Error( + `exchange ${exchangeDetails.exchangeBaseUrl} doesn't have fees for wire type ${wireType} at ${time.t_s}`, + ); + } + + return fee; +} + export async function trackDepositGroup( ws: InternalWalletState, req: TrackDepositGroupRequest, diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index 3e396098e..c0045aced 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -764,6 +764,7 @@ function buildTransactionForDeposit( deposited = false; } } + return { type: TransactionType.Deposit, amountRaw: Amounts.stringify(dg.effectiveDepositAmount), @@ -788,6 +789,7 @@ function buildTransactionForDeposit( )) / dg.transactionPerCoin.length, depositGroupId: dg.depositGroupId, + trackingState: Object.values(dg.trackingState ?? {}), deposited, ...(ort?.lastError ? { error: ort.lastError } : {}), }; -- cgit v1.2.3