diff options
author | Sebastian <sebasjm@gmail.com> | 2024-05-20 12:48:44 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-05-20 12:48:44 -0300 |
commit | abafae8a1bf5b8b22b09438eac1d2292b6f836f2 (patch) | |
tree | 9c41e2f19cb40dd112521087ddfc0d78d799b913 /packages/taler-wallet-core/src | |
parent | 184c3bcd2d7aabbc033b035fda34e86b3df2f98a (diff) | |
download | wallet-core-abafae8a1bf5b8b22b09438eac1d2292b6f836f2.tar.xz |
fix #8856 #8840
Diffstat (limited to 'packages/taler-wallet-core/src')
-rw-r--r-- | packages/taler-wallet-core/src/balance.ts | 3 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/db.ts | 4 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/transactions.ts | 86 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet.ts | 1 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/withdraw.ts | 123 |
5 files changed, 109 insertions, 108 deletions
diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts index e4783350c..b2ba7b95d 100644 --- a/packages/taler-wallet-core/src/balance.ts +++ b/packages/taler-wallet-core/src/balance.ts @@ -376,7 +376,6 @@ export async function getBalancesInsideTransaction( case WithdrawalGroupStatus.SuspendedKyc: case WithdrawalGroupStatus.PendingKyc: { checkDbInvariant(wg.denomsSel !== undefined, "wg in kyc state should have been initialized") - checkDbInvariant(wg.exchangeBaseUrl !== undefined, "wg in kyc state should have been initialized") const currency = Amounts.currencyOf(wg.denomsSel.totalCoinValue); await balanceStore.setFlagIncomingKyc(currency, wg.exchangeBaseUrl); break; @@ -384,7 +383,6 @@ export async function getBalancesInsideTransaction( case WithdrawalGroupStatus.PendingAml: case WithdrawalGroupStatus.SuspendedAml: { checkDbInvariant(wg.denomsSel !== undefined, "wg in aml state should have been initialized") - checkDbInvariant(wg.exchangeBaseUrl !== undefined, "wg in aml state should have been initialized") const currency = Amounts.currencyOf(wg.denomsSel.totalCoinValue); await balanceStore.setFlagIncomingAml(currency, wg.exchangeBaseUrl); break; @@ -401,7 +399,6 @@ export async function getBalancesInsideTransaction( } case WithdrawalGroupStatus.PendingWaitConfirmBank: { checkDbInvariant(wg.denomsSel !== undefined, "wg in confirmed state should have been initialized") - checkDbInvariant(wg.exchangeBaseUrl !== undefined, "wg in confirmed state should have been initialized") const currency = Amounts.currencyOf(wg.denomsSel.totalCoinValue); await balanceStore.setFlagIncomingConfirmation( currency, diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index e5bc1c9e9..9d963b269 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -393,6 +393,8 @@ export interface ReserveBankInfo { * Set to undefined if not confirmed yet. */ timestampBankConfirmed: DbPreciseTimestamp | undefined; + + wireTypes: string[] | undefined; } /** @@ -1528,7 +1530,7 @@ export interface WithdrawalGroupRecord { * The exchange base URL that we're withdrawing from. * (Redundantly stored, as the reserve record also has this info.) */ - exchangeBaseUrl?: string; + exchangeBaseUrl: string; /** * When was the withdrawal operation started started? diff --git a/packages/taler-wallet-core/src/transactions.ts b/packages/taler-wallet-core/src/transactions.ts index f36380033..b4809bfed 100644 --- a/packages/taler-wallet-core/src/transactions.ts +++ b/packages/taler-wallet-core/src/transactions.ts @@ -93,6 +93,7 @@ import { computeDenomLossTransactionStatus, DenomLossTransactionContext, ExchangeWireDetails, + fetchFreshExchange, getExchangeWireDetailsInTx, } from "./exchanges.js"; import { @@ -243,24 +244,22 @@ export async function getTransactionById( const opId = TaskIdentifiers.forWithdrawal(withdrawalGroupRecord); const ort = await tx.operationRetries.get(opId); + const exchangeDetails = await getExchangeWireDetailsInTx( + tx, + withdrawalGroupRecord.exchangeBaseUrl, + ); + if (!exchangeDetails) throw Error("not exchange details"); + if ( withdrawalGroupRecord.wgInfo.withdrawalType === WithdrawalRecordType.BankIntegrated ) { return buildTransactionForBankIntegratedWithdraw( withdrawalGroupRecord, + exchangeDetails, ort, ); } - checkDbInvariant( - withdrawalGroupRecord.exchangeBaseUrl !== undefined, - "manual withdraw should have exchange url", - ); - const exchangeDetails = await getExchangeWireDetailsInTx( - tx, - withdrawalGroupRecord.exchangeBaseUrl, - ); - if (!exchangeDetails) throw Error("not exchange details"); return buildTransactionForManualWithdraw( withdrawalGroupRecord, @@ -595,7 +594,6 @@ function buildTransactionForPeerPullCredit( const txState = computePeerPullCreditTransactionState(pullCredit); checkDbInvariant(wsr.instructedAmount !== undefined, "wg unitialized"); checkDbInvariant(wsr.denomsSel !== undefined, "wg unitialized"); - checkDbInvariant(wsr.exchangeBaseUrl !== undefined, "wg unitialized"); return { type: TransactionType.PeerPullCredit, txState, @@ -670,7 +668,6 @@ function buildTransactionForPeerPushCredit( } checkDbInvariant(wg.instructedAmount !== undefined, "wg unitialized"); checkDbInvariant(wg.denomsSel !== undefined, "wg unitialized"); - checkDbInvariant(wg.exchangeBaseUrl !== undefined, "wg unitialized"); const txState = computePeerPushCreditTransactionState(pushInc); return { @@ -723,23 +720,28 @@ function buildTransactionForPeerPushCredit( function buildTransactionForBankIntegratedWithdraw( wg: WithdrawalGroupRecord, + exchangeDetails: ExchangeWireDetails, ort?: OperationRetryRecord, ): TransactionWithdrawal { - if (wg.wgInfo.withdrawalType !== WithdrawalRecordType.BankIntegrated) + if (wg.wgInfo.withdrawalType !== WithdrawalRecordType.BankIntegrated) { throw Error(""); - + } const txState = computeWithdrawalTransactionStatus(wg); - checkDbInvariant(wg.instructedAmount !== undefined, "wg unitialized"); - checkDbInvariant(wg.denomsSel !== undefined, "wg unitialized"); - checkDbInvariant(wg.exchangeBaseUrl !== undefined, "wg unitialized"); + const zero = Amounts.stringify( + Amounts.zeroOfCurrency(exchangeDetails.currency), + ); return { type: TransactionType.Withdrawal, txState, txActions: computeWithdrawalTransactionActions(wg), - amountEffective: isUnsuccessfulTransaction(txState) - ? Amounts.stringify(Amounts.zeroOfAmount(wg.instructedAmount)) - : Amounts.stringify(wg.denomsSel.totalCoinValue), - amountRaw: Amounts.stringify(wg.instructedAmount), + exchangeBaseUrl: wg.exchangeBaseUrl, + amountEffective: + isUnsuccessfulTransaction(txState) || !wg.denomsSel + ? zero + : Amounts.stringify(wg.denomsSel.totalCoinValue), + amountRaw: !wg.instructedAmount + ? zero + : Amounts.stringify(wg.instructedAmount), withdrawalDetails: { type: WithdrawalType.TalerBankIntegrationApi, confirmed: wg.wgInfo.bankInfo.timestampBankConfirmed ? true : false, @@ -751,7 +753,6 @@ function buildTransactionForBankIntegratedWithdraw( wg.status === WithdrawalGroupStatus.PendingReady, }, kycUrl: wg.kycUrl, - exchangeBaseUrl: wg.exchangeBaseUrl, timestamp: timestampPreciseFromDb(wg.timestampStart), transactionId: constructTransactionIdentifier({ tag: TransactionType.Withdrawal, @@ -784,7 +785,6 @@ function buildTransactionForManualWithdraw( checkDbInvariant(wg.instructedAmount !== undefined, "wg unitialized"); checkDbInvariant(wg.denomsSel !== undefined, "wg unitialized"); - checkDbInvariant(wg.exchangeBaseUrl !== undefined, "wg unitialized"); const exchangePaytoUris = augmentPaytoUrisForWithdrawal( plainPaytoUris, wg.reservePub, @@ -996,12 +996,12 @@ async function lookupMaybeContractData( return contractData; } -async function buildTransactionForPurchase( +function buildTransactionForPurchase( purchaseRecord: PurchaseRecord, contractData: WalletContractData, refundsInfo: RefundGroupRecord[], ort?: OperationRetryRecord, -): Promise<Transaction> { +): Transaction { const zero = Amounts.zeroOfAmount(contractData.amount); const info: OrderShortInfo = { @@ -1094,24 +1094,22 @@ export async function getWithdrawalTransactionByUri( const opId = TaskIdentifiers.forWithdrawal(withdrawalGroupRecord); const ort = await tx.operationRetries.get(opId); + const exchangeDetails = await getExchangeWireDetailsInTx( + tx, + withdrawalGroupRecord.exchangeBaseUrl, + ); + if (!exchangeDetails) throw Error("not exchange details"); + if ( withdrawalGroupRecord.wgInfo.withdrawalType === WithdrawalRecordType.BankIntegrated ) { return buildTransactionForBankIntegratedWithdraw( withdrawalGroupRecord, + exchangeDetails, ort, ); } - checkDbInvariant( - withdrawalGroupRecord.exchangeBaseUrl !== undefined, - "manual withdraw should have exchange url", - ); - const exchangeDetails = await getExchangeWireDetailsInTx( - tx, - withdrawalGroupRecord.exchangeBaseUrl, - ); - if (!exchangeDetails) throw Error("not exchange details"); return buildTransactionForManualWithdraw( withdrawalGroupRecord, @@ -1390,11 +1388,26 @@ export async function getTransactions( // FIXME: If this is an orphan withdrawal, still report it as a withdrawal! // FIXME: Still report if requested with verbose option? return; - case WithdrawalRecordType.BankIntegrated: + case WithdrawalRecordType.BankIntegrated: { + const exchangeDetails = await getExchangeWireDetailsInTx( + tx, + wsr.exchangeBaseUrl, + ); + if (!exchangeDetails) { + // FIXME: report somehow + return; + } + transactions.push( - buildTransactionForBankIntegratedWithdraw(wsr, ort), + buildTransactionForBankIntegratedWithdraw( + wsr, + exchangeDetails, + ort, + ), ); return; + } + case WithdrawalRecordType.BankManual: { const exchangeDetails = await getExchangeWireDetailsInTx( tx, @@ -1404,7 +1417,6 @@ export async function getTransactions( // FIXME: report somehow return; } - transactions.push( buildTransactionForManualWithdraw(wsr, exchangeDetails, ort), ); @@ -1505,7 +1517,7 @@ export async function getTransactions( ); transactions.push( - await buildTransactionForPurchase( + buildTransactionForPurchase( purchase, contractData, refunds, diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 4bff23fd5..26fd64eb4 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -1007,6 +1007,7 @@ async function dispatchRequestInternal( codecForPrepareBankIntegratedWithdrawalRequest().decode(payload); return prepareBankIntegratedWithdrawal(wex, { talerWithdrawUri: req.talerWithdrawUri, + selectedExchange: req.selectedExchange, }); } case WalletApiOperation.GetExchangeTos: { diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts index d14689b12..b95ab8548 100644 --- a/packages/taler-wallet-core/src/withdraw.ts +++ b/packages/taler-wallet-core/src/withdraw.ts @@ -235,10 +235,6 @@ async function updateWithdrawalTransaction( wgRecord.wgInfo.withdrawalType === WithdrawalRecordType.BankManual ) { checkDbInvariant( - wgRecord.exchangeBaseUrl !== undefined, - "manual withdrawal without exchange can't be created", - ); - checkDbInvariant( wgRecord.instructedAmount !== undefined, "manual withdrawal without amount can't be created", ); @@ -918,10 +914,6 @@ async function processPlanchetGenerate( coinIdx: number, ): Promise<void> { checkDbInvariant( - withdrawalGroup.exchangeBaseUrl !== undefined, - "can't process unitialized exchange", - ); - checkDbInvariant( withdrawalGroup.denomsSel !== undefined, "can't process unitialized exchange", ); @@ -1129,10 +1121,6 @@ async function processPlanchetExchangeBatchRequest( logger.info( `processing planchet exchange batch request ${withdrawalGroup.withdrawalGroupId}, start=${args.coinStartIndex}, len=${args.batchSize}`, ); - checkDbInvariant( - withdrawalGroup.exchangeBaseUrl !== undefined, - "can't process unitialized exchange", - ); const exchangeBaseUrl = withdrawalGroup.exchangeBaseUrl; const batchReq: ExchangeBatchWithdrawRequest = { planchets: [] }; @@ -1268,10 +1256,6 @@ async function processPlanchetVerifyAndStoreCoin( resp: ExchangeWithdrawResponse, ): Promise<void> { const withdrawalGroup = wgContext.wgRecord; - checkDbInvariant( - withdrawalGroup.exchangeBaseUrl !== undefined, - "can't process unitialized exchange", - ); const exchangeBaseUrl = withdrawalGroup.exchangeBaseUrl; logger.trace(`checking and storing planchet idx=${coinIdx}`); @@ -1454,7 +1438,8 @@ export async function updateWithdrawalDenoms( denom.verificationStatus === DenominationVerificationStatus.Unverified ) { logger.trace( - `Validating denomination (${current + 1}/${denominations.length + `Validating denomination (${current + 1}/${ + denominations.length }) signature of ${denom.denomPubHash}`, ); let valid = false; @@ -1520,10 +1505,6 @@ async function processQueryReserve( return TaskRunResult.backoff(); } checkDbInvariant( - withdrawalGroup.exchangeBaseUrl !== undefined, - "can't process unitialized exchange", - ); - checkDbInvariant( withdrawalGroup.denomsSel !== undefined, "can't process unitialized exchange", ); @@ -1576,8 +1557,10 @@ async function processQueryReserve( ) { amountChanged = true; } - console.log(`amount change ${j2s(result.response)}`) - console.log(`amount change ${j2s(withdrawalGroup.denomsSel.totalWithdrawCost)}`) + console.log(`amount change ${j2s(result.response)}`); + console.log( + `amount change ${j2s(withdrawalGroup.denomsSel.totalWithdrawCost)}`, + ); const exchangeBaseUrl = withdrawalGroup.exchangeBaseUrl; const currency = Amounts.currencyOf(withdrawalGroup.instructedAmount); @@ -1757,10 +1740,6 @@ async function redenominateWithdrawal( return; } checkDbInvariant( - wg.exchangeBaseUrl !== undefined, - "can't process unitialized exchange", - ); - checkDbInvariant( wg.denomsSel !== undefined, "can't process unitialized exchange", ); @@ -1900,10 +1879,6 @@ async function processWithdrawalGroupPendingReady( const ctx = new WithdrawTransactionContext(wex, withdrawalGroupId); checkDbInvariant( - withdrawalGroup.exchangeBaseUrl !== undefined, - "can't process unitialized exchange", - ); - checkDbInvariant( withdrawalGroup.denomsSel !== undefined, "can't process unitialized exchange", ); @@ -2215,7 +2190,7 @@ export async function getExchangeWithdrawalInfo( ) { logger.warn( `wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` + - `(exchange has ${exchange.protocolVersionRange}), checking for updates`, + `(exchange has ${exchange.protocolVersionRange}), checking for updates`, ); } } @@ -2333,10 +2308,6 @@ export async function getFundingPaytoUris( const withdrawalGroup = await tx.withdrawalGroups.get(withdrawalGroupId); checkDbInvariant(!!withdrawalGroup); checkDbInvariant( - withdrawalGroup.exchangeBaseUrl !== undefined, - "can't get funding uri from uninitialized wg", - ); - checkDbInvariant( withdrawalGroup.instructedAmount !== undefined, "can't get funding uri from uninitialized wg", ); @@ -2684,7 +2655,7 @@ export async function internalPrepareCreateWithdrawalGroup( args: { reserveStatus: WithdrawalGroupStatus; amount?: AmountJson; - exchangeBaseUrl?: string; + exchangeBaseUrl: string; forcedWithdrawalGroupId?: string; forcedDenomSel?: ForcedDenomSel; reserveKeyPair?: EddsaKeypair; @@ -2725,19 +2696,11 @@ export async function internalPrepareCreateWithdrawalGroup( let initialDenomSel: DenomSelectionState | undefined; const denomSelUid = encodeCrock(getRandomBytes(16)); - const creationInfo = - exchangeBaseUrl !== undefined && amount !== undefined - ? { - canonExchange: exchangeBaseUrl, - amount, - } - : undefined; - - if (creationInfo) { + if (amount !== undefined) { initialDenomSel = await getInitialDenomsSelection( wex, - creationInfo.canonExchange, - creationInfo.amount, + exchangeBaseUrl, + amount, args.forcedDenomSel, ); } @@ -2764,9 +2727,7 @@ export async function internalPrepareCreateWithdrawalGroup( wgInfo: args.wgInfo, }; - if (creationInfo) { - await fetchFreshExchange(wex, creationInfo.canonExchange); - } + await fetchFreshExchange(wex, exchangeBaseUrl); const transactionId = constructTransactionIdentifier({ tag: TransactionType.Withdrawal, @@ -2776,7 +2737,12 @@ export async function internalPrepareCreateWithdrawalGroup( return { withdrawalGroup, transactionId, - creationInfo, + creationInfo: !amount + ? undefined + : { + amount, + canonExchange: exchangeBaseUrl, + }, }; } @@ -2871,8 +2837,8 @@ export async function internalCreateWithdrawalGroup( wex: WalletExecutionContext, args: { reserveStatus: WithdrawalGroupStatus; + exchangeBaseUrl: string; amount?: AmountJson; - exchangeBaseUrl?: string; forcedWithdrawalGroupId?: string; forcedDenomSel?: ForcedDenomSel; reserveKeyPair?: EddsaKeypair; @@ -2917,6 +2883,7 @@ export async function prepareBankIntegratedWithdrawal( wex: WalletExecutionContext, req: { talerWithdrawUri: string; + selectedExchange?: string; }, ): Promise<PrepareBankIntegratedWithdrawalResponse> { const existingWithdrawalGroup = await wex.db.runReadOnlyTx( @@ -2929,13 +2896,6 @@ export async function prepareBankIntegratedWithdrawal( ); if (existingWithdrawalGroup) { - let url: string | undefined; - if ( - existingWithdrawalGroup.wgInfo.withdrawalType === - WithdrawalRecordType.BankIntegrated - ) { - url = existingWithdrawalGroup.wgInfo.bankInfo.confirmUrl; - } const info = await getWithdrawalDetailsForUri(wex, req.talerWithdrawUri); return { transactionId: constructTransactionIdentifier({ @@ -2945,6 +2905,18 @@ export async function prepareBankIntegratedWithdrawal( info, }; } + const withdrawInfo = await getBankWithdrawalInfo( + wex.http, + req.talerWithdrawUri, + ); + + const info = await getWithdrawalDetailsForUri(wex, req.talerWithdrawUri); + + const exchangeBaseUrl = + req.selectedExchange ?? withdrawInfo.suggestedExchange; + if (!exchangeBaseUrl) { + return { info }; + } /** * Withdrawal group without exchange and amount @@ -2954,20 +2926,20 @@ export async function prepareBankIntegratedWithdrawal( * same URI */ const withdrawalGroup = await internalCreateWithdrawalGroup(wex, { + exchangeBaseUrl, wgInfo: { withdrawalType: WithdrawalRecordType.BankIntegrated, bankInfo: { talerWithdrawUri: req.talerWithdrawUri, - confirmUrl: undefined, + confirmUrl: withdrawInfo.confirmTransferUrl, timestampBankConfirmed: undefined, timestampReserveInfoPosted: undefined, + wireTypes: withdrawInfo.wireTypes, }, }, reserveStatus: WithdrawalGroupStatus.DialogProposed, }); - const info = await getWithdrawalDetailsForUri(wex, req.talerWithdrawUri); - const withdrawalGroupId = withdrawalGroup.withdrawalGroupId; const ctx = new WithdrawTransactionContext(wex, withdrawalGroupId); @@ -3010,19 +2982,34 @@ export async function confirmWithdrawal( const exchange = await fetchFreshExchange(wex, selectedExchange); const talerWithdrawUri = withdrawalGroup.wgInfo.bankInfo.talerWithdrawUri; + const confirmUrl = withdrawalGroup.wgInfo.bankInfo.confirmUrl; + + /** + * The only reasong this to be undefined is because it is an old wallet + * database before adding the wireType field was added + */ + let wtypes: string[]; + if (withdrawalGroup.wgInfo.bankInfo.wireTypes === undefined) { + const withdrawInfo = await getBankWithdrawalInfo( + wex.http, + talerWithdrawUri, + ); + wtypes = withdrawInfo.wireTypes; + } else { + wtypes = withdrawalGroup.wgInfo.bankInfo.wireTypes; + } - const withdrawInfo = await getBankWithdrawalInfo(wex.http, talerWithdrawUri); const exchangePaytoUri = await getExchangePaytoUri( wex, selectedExchange, - withdrawInfo.wireTypes, + wtypes, ); const withdrawalAccountList = await fetchWithdrawalAccountInfo( wex, { exchange, - instructedAmount: withdrawInfo.amount, + instructedAmount: Amounts.parseOrThrow(req.amount), }, wex.cancellationToken, ); @@ -3057,9 +3044,10 @@ export async function confirmWithdrawal( bankInfo: { exchangePaytoUri, talerWithdrawUri, - confirmUrl: withdrawInfo.confirmTransferUrl, + confirmUrl: confirmUrl, timestampBankConfirmed: undefined, timestampReserveInfoPosted: undefined, + wireTypes: wtypes, }, }; @@ -3157,6 +3145,7 @@ export async function acceptWithdrawalFromUri( confirmUrl: withdrawInfo.confirmTransferUrl, timestampBankConfirmed: undefined, timestampReserveInfoPosted: undefined, + wireTypes: withdrawInfo.wireTypes, }, }, restrictAge: req.restrictAge, |