aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-05-23 19:50:59 +0200
committerFlorian Dold <florian@dold.me>2024-05-23 19:50:59 +0200
commitcdcedf65595393fc186eb2012d3ae6cd55540f59 (patch)
tree88c4eecce4673c1c2b7b3b6eaadfb4b7f8df0ce8 /packages/taler-wallet-core
parent527716758f154eb863acb0052f004dd23313f765 (diff)
downloadwallet-core-cdcedf65595393fc186eb2012d3ae6cd55540f59.tar.xz
wallet-core: support bank-integrated withdrawal with amount selection by wallet
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/src/db.ts1
-rw-r--r--packages/taler-wallet-core/src/shepherd.ts8
-rw-r--r--packages/taler-wallet-core/src/wallet.ts5
-rw-r--r--packages/taler-wallet-core/src/withdraw.ts58
4 files changed, 58 insertions, 14 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 44c241aed..640d94753 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1439,6 +1439,7 @@ export interface WgInfoBankIntegrated {
* a Taler-integrated bank.
*/
bankInfo: ReserveBankInfo;
+
/**
* Info about withdrawal accounts, possibly including currency conversion.
*/
diff --git a/packages/taler-wallet-core/src/shepherd.ts b/packages/taler-wallet-core/src/shepherd.ts
index dbdd7aac5..d662bd7ae 100644
--- a/packages/taler-wallet-core/src/shepherd.ts
+++ b/packages/taler-wallet-core/src/shepherd.ts
@@ -382,7 +382,13 @@ export class TaskSchedulerImpl implements TaskScheduler {
});
switch (res.type) {
case TaskRunResultType.Error: {
- logger.trace(`Shepherd for ${taskId} got error result.`);
+ if (logger.shouldLogTrace()) {
+ logger.trace(
+ `Shepherd for ${taskId} got error result: ${j2s(
+ res.errorDetail,
+ )}`,
+ );
+ }
const retryRecord = await storePendingTaskError(
this.ws,
taskId,
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index c17a2b467..3455d451b 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -724,7 +724,9 @@ async function dispatchRequestInternal(
const req = codecForInitRequest().decode(payload);
if (logger.shouldLogTrace()) {
- const initType = wex.ws.initCalled ? "repeat initialization" : "first initialization";
+ const initType = wex.ws.initCalled
+ ? "repeat initialization"
+ : "first initialization";
logger.trace(`init request (${initType}): ${j2s(req)}`);
}
@@ -997,6 +999,7 @@ async function dispatchRequestInternal(
talerWithdrawUri: req.talerWithdrawUri,
forcedDenomSel: req.forcedDenomSel,
restrictAge: req.restrictAge,
+ amount: req.amount,
});
}
case WalletApiOperation.ConfirmWithdrawal: {
diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts
index 4a7c7873c..16289b1ef 100644
--- a/packages/taler-wallet-core/src/withdraw.ts
+++ b/packages/taler-wallet-core/src/withdraw.ts
@@ -857,10 +857,16 @@ export async function getBankWithdrawalInfo(
}
const { body: status } = resp;
+ let amount: AmountJson | undefined;
+ if (status.amount) {
+ amount = Amounts.parseOrThrow(status.amount);
+ }
+
return {
operationId: uriResult.withdrawalOperationId,
apiBaseUrl: uriResult.bankIntegrationApiBaseUrl,
- amount: Amounts.parseOrThrow(status.amount),
+ currency: config.currency,
+ amount,
confirmTransferUrl: status.confirm_transfer_url,
senderWire: status.sender_wire,
suggestedExchange: status.suggested_exchange,
@@ -2262,7 +2268,7 @@ export async function getWithdrawalDetailsForUri(
}
}
- const currency = Amounts.currencyOf(info.amount);
+ const currency = info.currency;
const listExchangesResp = await listExchanges(wex);
const possibleExchanges = listExchangesResp.exchanges.filter((x) => {
@@ -2277,7 +2283,8 @@ export async function getWithdrawalDetailsForUri(
operationId: info.operationId,
confirmTransferUrl: info.confirmTransferUrl,
status: info.status,
- amount: Amounts.stringify(info.amount),
+ currency,
+ amount: info.amount ? Amounts.stringify(info.amount) : undefined,
defaultExchangeBaseUrl: info.suggestedExchange,
possibleExchanges,
};
@@ -2379,6 +2386,7 @@ export function getBankAbortUrl(talerWithdrawUri: string): string {
async function registerReserveWithBank(
wex: WalletExecutionContext,
withdrawalGroupId: string,
+ isFlexibleAmount: boolean,
): Promise<void> {
const withdrawalGroup = await wex.db.runReadOnlyTx(
{ storeNames: ["withdrawalGroups"] },
@@ -2407,7 +2415,11 @@ async function registerReserveWithBank(
const reqBody = {
reserve_pub: withdrawalGroup.reservePub,
selected_exchange: bankInfo.exchangePaytoUri,
- };
+ } as any;
+ if (isFlexibleAmount) {
+ reqBody.amount = withdrawalGroup.instructedAmount;
+ }
+ logger.trace(`isFlexibleAmount: ${isFlexibleAmount}`);
logger.info(`registering reserve with bank: ${j2s(reqBody)}`);
const httpResp = await wex.http.fetch(bankStatusUrl, {
method: "POST",
@@ -2516,7 +2528,9 @@ async function processBankRegisterReserve(
// FIXME: Put confirm transfer URL in the DB!
- await registerReserveWithBank(wex, withdrawalGroupId);
+ const isFlexibleAmount = status.amount == null;
+
+ await registerReserveWithBank(wex, withdrawalGroupId, isFlexibleAmount);
return TaskRunResult.progress();
}
@@ -2985,7 +2999,7 @@ export async function confirmWithdrawal(
const confirmUrl = withdrawalGroup.wgInfo.bankInfo.confirmUrl;
/**
- * The only reasong this to be undefined is because it is an old wallet
+ * The only reason this could be undefined is because it is an old wallet
* database before adding the wireType field was added
*/
let wtypes: string[];
@@ -3025,7 +3039,7 @@ export async function confirmWithdrawal(
req.forcedDenomSel,
);
- ctx.transition({}, async (rec) => {
+ await ctx.transition({}, async (rec) => {
if (!rec) {
return TransitionResult.stay();
}
@@ -3060,7 +3074,6 @@ export async function confirmWithdrawal(
});
await wex.taskScheduler.resetTaskRetries(ctx.taskId);
- wex.taskScheduler.startShepherdTask(ctx.taskId);
}
/**
@@ -3080,6 +3093,7 @@ export async function acceptWithdrawalFromUri(
selectedExchange: string;
forcedDenomSel?: ForcedDenomSel;
restrictAge?: number;
+ amount?: AmountLike;
},
): Promise<AcceptWithdrawalResponse> {
const selectedExchange = req.selectedExchange;
@@ -3124,17 +3138,37 @@ export async function acceptWithdrawalFromUri(
withdrawInfo.wireTypes,
);
+ let amount: AmountJson;
+ if (withdrawInfo.amount == null) {
+ if (req.amount == null) {
+ throw Error(
+ "amount required, as withdrawal operation has flexible amount",
+ );
+ }
+ amount = Amounts.parseOrThrow(req.amount);
+ } else {
+ if (
+ req.amount != null &&
+ Amounts.cmp(req.amount, withdrawInfo.amount) != 0
+ ) {
+ throw Error(
+ "mismatched amount, amount is fixed by bank but client provided different amount",
+ );
+ }
+ amount = withdrawInfo.amount;
+ }
+
const withdrawalAccountList = await fetchWithdrawalAccountInfo(
wex,
{
exchange,
- instructedAmount: withdrawInfo.amount,
+ instructedAmount: amount,
},
CancellationToken.CONTINUE,
);
const withdrawalGroup = await internalCreateWithdrawalGroup(wex, {
- amount: withdrawInfo.amount,
+ amount,
exchangeBaseUrl: req.selectedExchange,
wgInfo: {
withdrawalType: WithdrawalRecordType.BankIntegrated,
@@ -3162,10 +3196,10 @@ export async function acceptWithdrawalFromUri(
hintTransactionId: ctx.transactionId,
});
- await waitWithdrawalRegistered(wex, ctx);
-
wex.taskScheduler.startShepherdTask(ctx.taskId);
+ await waitWithdrawalRegistered(wex, ctx);
+
return {
reservePub: withdrawalGroup.reservePub,
confirmTransferUrl: withdrawInfo.confirmTransferUrl,