commit f401ab076bb037e46c4b12e371dfe13a777bf582
parent c93889d3c84f2019a58b078eeea86ab523d16139
Author: Florian Dold <florian@dold.me>
Date: Wed, 11 Sep 2024 16:29:50 +0200
wallet-core: support restricting scope for peer push payments
Diffstat:
5 files changed, 59 insertions(+), 1 deletion(-)
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
@@ -2750,6 +2750,12 @@ export interface CheckPeerPushDebitRequest {
amount: AmountString;
/**
+ * Restrict the scope of funds that can be spent via the given
+ * scope info.
+ */
+ restrictScope?: ScopeInfo;
+
+ /**
* ID provided by the client to cancel the request.
*
* If the same request is made again with the same clientCancellationId,
@@ -2789,6 +2795,13 @@ export interface CheckPeerPushDebitResponse {
export interface InitiatePeerPushDebitRequest {
exchangeBaseUrl?: string;
+
+ /**
+ * Restrict the scope of funds that can be spent via the given
+ * scope info.
+ */
+ restrictScope?: ScopeInfo;
+
partialContractTerms: PeerContractTerms;
}
diff --git a/packages/taler-wallet-core/src/coinSelection.ts b/packages/taler-wallet-core/src/coinSelection.ts
@@ -46,6 +46,8 @@ import {
PayCoinSelection,
PaymentInsufficientBalanceDetails,
ProspectivePayCoinSelection,
+ ScopeInfo,
+ ScopeType,
SelectedCoin,
SelectedProspectiveCoin,
strcmp,
@@ -55,6 +57,7 @@ import { getPaymentBalanceDetailsInTx } from "./balance.js";
import { getAutoRefreshExecuteThreshold } from "./common.js";
import { DenominationRecord, WalletDbReadOnlyTransaction } from "./db.js";
import {
+ checkExchangeInScope,
ExchangeWireDetails,
getExchangeWireDetailsInTx,
} from "./exchanges.js";
@@ -993,6 +996,12 @@ export interface PeerCoinSelectionRequest {
instructedAmount: AmountJson;
/**
+ * Restrict the scope of funds that can be spent via the given
+ * scope info.
+ */
+ restrictScope?: ScopeInfo;
+
+ /**
* Instruct the coin selection to repair this coin
* selection instead of selecting completely new coins.
*/
@@ -1165,6 +1174,19 @@ export async function selectPeerCoinsInTx(
if (!exchWire) {
continue;
}
+ const isInScope = req.restrictScope
+ ? await checkExchangeInScope(wex, exch.baseUrl, req.restrictScope)
+ : true;
+ if (!isInScope) {
+ continue;
+ }
+ if (
+ req.restrictScope &&
+ req.restrictScope.type === ScopeType.Exchange &&
+ req.restrictScope.url !== exch.baseUrl
+ ) {
+ continue;
+ }
const globalFees = getGlobalFees(exchWire);
if (!globalFees) {
continue;
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
@@ -1898,6 +1898,13 @@ export interface PeerPushDebitRecord {
exchangeBaseUrl: string;
/**
+ * Restricted scope for this transaction.
+ *
+ * Relevant for coin reselection.
+ */
+ restrictScope?: ScopeInfo;
+
+ /**
* Instructed amount.
*/
amount: AmountString;
diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts
@@ -3571,3 +3571,14 @@ export async function processExchangeKyc(
);
}
}
+
+export async function checkExchangeInScope(
+ wex: WalletExecutionContext,
+ exchangeBaseUrl: string,
+ scope: ScopeInfo,
+): Promise<boolean> {
+ if (scope.type === ScopeType.Exchange && scope.url !== exchangeBaseUrl) {
+ return false;
+ }
+ return true;
+}
diff --git a/packages/taler-wallet-core/src/pay-peer-push-debit.ts b/packages/taler-wallet-core/src/pay-peer-push-debit.ts
@@ -80,6 +80,7 @@ import {
timestampProtocolFromDb,
timestampProtocolToDb,
} from "./db.js";
+import { getScopeForAllExchanges } from "./exchanges.js";
import {
codecForExchangePurseStatus,
getTotalPeerPaymentCost,
@@ -93,7 +94,6 @@ import {
notifyTransition,
} from "./transactions.js";
import { WalletExecutionContext } from "./wallet.js";
-import { getScopeForAllExchanges } from "./exchanges.js";
const logger = new Logger("pay-peer-push-debit.ts");
@@ -455,6 +455,7 @@ async function internalCheckPeerPushDebit(
);
const coinSelRes = await selectPeerCoins(wex, {
instructedAmount,
+ restrictScope: req.restrictScope,
});
let coins: SelectedProspectiveCoin[] | undefined = undefined;
switch (coinSelRes.type) {
@@ -528,6 +529,7 @@ async function handlePurseCreationConflict(
const coinSelRes = await selectPeerCoins(wex, {
instructedAmount,
+ restrictScope: peerPushInitiation.restrictScope,
repair,
});
@@ -599,6 +601,7 @@ async function processPeerPushDebitCreateReserve(
if (!peerPushInitiation.coinSel) {
const coinSelRes = await selectPeerCoins(wex, {
instructedAmount: Amounts.parseOrThrow(peerPushInitiation.amount),
+ restrictScope: peerPushInitiation.restrictScope,
});
switch (coinSelRes.type) {
@@ -1228,6 +1231,7 @@ export async function initiatePeerPushDebit(
async (tx) => {
const coinSelRes = await selectPeerCoinsInTx(wex, tx, {
instructedAmount,
+ restrictScope: req.restrictScope,
});
let coins: SelectedProspectiveCoin[] | undefined = undefined;
@@ -1255,6 +1259,7 @@ export async function initiatePeerPushDebit(
const totalAmount = await getTotalPeerPaymentCostInTx(wex, tx, coins);
const ppi: PeerPushDebitRecord = {
amount: Amounts.stringify(instructedAmount),
+ restrictScope: req.restrictScope,
contractPriv: contractKeyPair.priv,
contractPub: contractKeyPair.pub,
contractTermsHash: hContractTerms,