aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-05-20 12:48:44 -0300
committerSebastian <sebasjm@gmail.com>2024-05-20 12:48:44 -0300
commitabafae8a1bf5b8b22b09438eac1d2292b6f836f2 (patch)
tree9c41e2f19cb40dd112521087ddfc0d78d799b913 /packages/taler-wallet-core
parent184c3bcd2d7aabbc033b035fda34e86b3df2f98a (diff)
downloadwallet-core-abafae8a1bf5b8b22b09438eac1d2292b6f836f2.tar.xz
fix #8856 #8840
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/src/balance.ts3
-rw-r--r--packages/taler-wallet-core/src/db.ts4
-rw-r--r--packages/taler-wallet-core/src/transactions.ts86
-rw-r--r--packages/taler-wallet-core/src/wallet.ts1
-rw-r--r--packages/taler-wallet-core/src/withdraw.ts123
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,