commit 08e5fafee3ecd140ef0c59f1183b7f592ad19e11
parent fccab85a58e5eed4a9c12816ab255bc8c8b92960
Author: Florian Dold <florian@dold.me>
Date: Wed, 11 Sep 2024 16:13:53 +0200
wallet-core: fix perExchange insufficient balance reporting
Also tests the expected behavior in the integration test
Diffstat:
8 files changed, 141 insertions(+), 43 deletions(-)
diff --git a/packages/taler-harness/src/harness/helpers.ts b/packages/taler-harness/src/harness/helpers.ts
@@ -109,6 +109,7 @@ export interface SimpleTestEnvironmentNg {
*/
export interface SimpleTestEnvironmentNg3 {
commonDb: DbInfo;
+ bank: BankService;
bankClient: TalerCorebankApiClient;
exchange: ExchangeService;
exchangeBankAccount: HarnessExchangeBankAccount;
@@ -475,7 +476,7 @@ export async function createSimpleTestkudosEnvironmentV3(
const exchangeBankPassword = "mypw";
const exchangePaytoUri = generateRandomPayto(exchangeBankUsername);
const wireGatewayApiBaseUrl = new URL(
- "accounts/exchange/taler-wire-gateway/",
+ `accounts/${exchangeBankUsername}/taler-wire-gateway/`,
bank.corebankApiBaseUrl,
).href;
@@ -539,7 +540,6 @@ export async function createSimpleTestkudosEnvironmentV3(
opts.additionalExchangeConfig(exchange);
}
await exchange.start();
- await exchange.pingUntilAvailable();
merchant.addExchange(exchange);
@@ -584,6 +584,7 @@ export async function createSimpleTestkudosEnvironmentV3(
merchant,
walletClient,
walletService,
+ bank,
bankClient,
exchangeBankAccount,
};
diff --git a/packages/taler-harness/src/integrationtests/test-fee-regression.ts b/packages/taler-harness/src/integrationtests/test-fee-regression.ts
@@ -189,6 +189,7 @@ export async function createMyTestkudosEnvironment(
walletClient,
walletService,
bankClient,
+ bank,
exchangeBankAccount: {
accountName: "",
accountPassword: "",
diff --git a/packages/taler-harness/src/integrationtests/test-kyc.ts b/packages/taler-harness/src/integrationtests/test-kyc.ts
@@ -265,6 +265,7 @@ async function createKycTestkudosEnvironment(
merchant,
walletClient,
walletService,
+ bank,
bankClient,
exchangeBankAccount: {
accountName: "",
diff --git a/packages/taler-harness/src/integrationtests/test-revocation.ts b/packages/taler-harness/src/integrationtests/test-revocation.ts
@@ -179,6 +179,7 @@ async function createTestEnvironment(
merchant,
walletClient,
walletService,
+ bank,
bankClient,
exchangeBankAccount: {
accountName: "",
diff --git a/packages/taler-harness/src/integrationtests/test-wallet-insufficient-balance.ts b/packages/taler-harness/src/integrationtests/test-wallet-insufficient-balance.ts
@@ -20,35 +20,78 @@
import {
AmountString,
Duration,
+ j2s,
PaymentInsufficientBalanceDetails,
TalerErrorCode,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
import {
- GlobalTestState,
+ ExchangeService,
generateRandomPayto,
+ GlobalTestState,
+ HarnessExchangeBankAccount,
setupDb,
} from "../harness/harness.js";
-import { createSimpleTestkudosEnvironmentV3, withdrawViaBankV3 } from "../harness/helpers.js";
+import {
+ createSimpleTestkudosEnvironmentV3,
+ withdrawViaBankV3,
+} from "../harness/helpers.js";
export async function runWalletInsufficientBalanceTest(t: GlobalTestState) {
// Set up test environment
- const db = await setupDb(t);
-
const coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => x("TESTKUDOS"));
- let {
- bankClient,
- exchange,
- merchant,
- walletService,
- walletClient,
- } = await createSimpleTestkudosEnvironmentV3(t, coinConfig, {
- skipWireFeeCreation: true,
+ let { bankClient, bank, exchange, merchant, walletClient } =
+ await createSimpleTestkudosEnvironmentV3(t, coinConfig, {
+ skipWireFeeCreation: true,
+ });
+
+ const dbTwo = await setupDb(t, {
+ nameSuffix: "two",
+ });
+
+ const exchangeTwo = ExchangeService.create(t, {
+ name: "testexchange-2",
+ currency: "TESTKUDOS",
+ httpPort: 9081,
+ database: dbTwo.connStr,
});
+ {
+ const receiverName = "Exchange2";
+ const exchangeBankUsername = "exchange2";
+ const exchangeBankPassword = "mypw";
+ const exchangePaytoUri = generateRandomPayto(exchangeBankUsername);
+ const wireGatewayApiBaseUrl = new URL(
+ `accounts/${exchangeBankUsername}/taler-wire-gateway/`,
+ bank.corebankApiBaseUrl,
+ ).href;
+
+ const exchangeBankAccount: HarnessExchangeBankAccount = {
+ wireGatewayApiBaseUrl,
+ accountName: exchangeBankUsername,
+ accountPassword: exchangeBankPassword,
+ accountPaytoUri: exchangePaytoUri,
+ skipWireFeeCreation: true,
+ };
+
+ await exchangeTwo.addBankAccount("1", exchangeBankAccount);
+
+ await bankClient.registerAccountExtended({
+ name: receiverName,
+ password: exchangeBankPassword,
+ username: exchangeBankUsername,
+ is_taler_exchange: true,
+ payto_uri: exchangePaytoUri,
+ });
+
+ exchangeTwo.addCoinConfigList(coinConfig);
+
+ await exchangeTwo.start();
+ }
+
await merchant.addInstanceWithWireAccount({
id: "default",
name: "Default Instance",
@@ -75,6 +118,8 @@ export async function runWalletInsufficientBalanceTest(t: GlobalTestState) {
},
});
+ t.logStep("setup-done");
+
const wres = await withdrawViaBankV3(t, {
amount: "TESTKUDOS:10",
bankClient,
@@ -83,29 +128,74 @@ export async function runWalletInsufficientBalanceTest(t: GlobalTestState) {
});
await wres.withdrawalFinishedCond;
- const exc = await t.assertThrowsTalerErrorAsync(async () => {
- await walletClient.call(WalletApiOperation.CheckDeposit, {
- amount: "TESTKUDOS:5" as AmountString,
- depositPaytoUri: "payto://x-taler-bank/localhost/foobar",
+ {
+ const exc = await t.assertThrowsTalerErrorAsync(async () => {
+ await walletClient.call(WalletApiOperation.CheckDeposit, {
+ amount: "TESTKUDOS:5" as AmountString,
+ depositPaytoUri: "payto://x-taler-bank/localhost/foobar",
+ });
+ });
+
+ t.assertDeepEqual(
+ exc.errorDetail.code,
+ TalerErrorCode.WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE,
+ );
+
+ const insufficientBalanceDetails: PaymentInsufficientBalanceDetails =
+ exc.errorDetail.insufficientBalanceDetails;
+
+ t.assertAmountEquals(
+ insufficientBalanceDetails.balanceAvailable,
+ "TESTKUDOS:9.72",
+ );
+ t.assertAmountEquals(
+ insufficientBalanceDetails.balanceExchangeDepositable,
+ "TESTKUDOS:0",
+ );
+ }
+
+ t.logStep("start-p2p-push-test");
+
+ // Now check for p2p-push
+
+ {
+ const wres2 = await withdrawViaBankV3(t, {
+ amount: "TESTKUDOS:5",
+ bankClient,
+ exchange: exchangeTwo,
+ walletClient,
+ });
+ await wres2.withdrawalFinishedCond;
+
+ const exc = await t.assertThrowsTalerErrorAsync(async () => {
+ await walletClient.call(WalletApiOperation.CheckPeerPushDebit, {
+ amount: "TESTKUDOS:20" as AmountString,
+ });
});
- });
- t.assertDeepEqual(
- exc.errorDetail.code,
- TalerErrorCode.WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE,
- );
-
- const insufficientBalanceDetails: PaymentInsufficientBalanceDetails =
- exc.errorDetail.insufficientBalanceDetails;
-
- t.assertAmountEquals(
- insufficientBalanceDetails.balanceAvailable,
- "TESTKUDOS:9.72",
- );
- t.assertAmountEquals(
- insufficientBalanceDetails.balanceExchangeDepositable,
- "TESTKUDOS:0",
- );
+ const insufficientBalanceDetails: PaymentInsufficientBalanceDetails =
+ exc.errorDetail.insufficientBalanceDetails;
+
+ const perMyExchange =
+ insufficientBalanceDetails.perExchange[exchange.baseUrl];
+
+ t.assertTrue(!!perMyExchange);
+
+ console.log(j2s(exc.errorDetail));
+
+ t.assertAmountEquals(
+ insufficientBalanceDetails.amountRequested,
+ "TESTKUDOS:20",
+ );
+ t.assertAmountEquals(
+ insufficientBalanceDetails.maxEffectiveSpendAmount,
+ "TESTKUDOS:14.22",
+ );
+ t.assertAmountEquals(
+ perMyExchange.maxEffectiveSpendAmount,
+ "TESTKUDOS:9.47",
+ );
+ }
}
runWalletInsufficientBalanceTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/test-wallettesting.ts b/packages/taler-harness/src/integrationtests/test-wallettesting.ts
@@ -44,7 +44,7 @@ export async function createMyEnvironment(
): Promise<SimpleTestEnvironmentNg3> {
const db = await setupDb(t);
- const { bankClient, exchange, merchant, exchangeBankAccount } =
+ const { bankClient, bank, exchange, merchant, exchangeBankAccount } =
await createSimpleTestkudosEnvironmentV3(t, coinConfig, {});
console.log("setup done!");
@@ -62,6 +62,7 @@ export async function createMyEnvironment(
merchant,
walletClient,
walletService,
+ bank,
bankClient,
exchangeBankAccount,
};
diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts
@@ -453,7 +453,6 @@ export async function getBalancesInsideTransaction(
case DepositOperationStatus.PendingAggregateKyc:
await balanceStore.setFlagOutgoingKyc(currency, e);
}
-
switch (dgRecord.operationStatus) {
case DepositOperationStatus.SuspendedAggregateKyc:
case DepositOperationStatus.PendingAggregateKyc:
diff --git a/packages/taler-wallet-core/src/coinSelection.ts b/packages/taler-wallet-core/src/coinSelection.ts
@@ -493,12 +493,16 @@ export async function reportInsufficientBalanceDetails(
let missingGlobalFees = false;
const exchWire = await getExchangeWireDetailsInTx(tx, exch.baseUrl);
if (!exchWire) {
+ // No wire details about the exchange known, skip!
+ continue;
+ }
+ const globalFees = getGlobalFees(exchWire);
+ if (!globalFees) {
missingGlobalFees = true;
- } else {
- const globalFees = getGlobalFees(exchWire);
- if (!globalFees) {
- missingGlobalFees = true;
- }
+ }
+ if (exchWire.currency !== Amounts.currencyOf(req.instructedAmount)) {
+ // Do not report anything for an exchange with a different currency.
+ continue;
}
const exchDet = await getPaymentBalanceDetailsInTx(wex, tx, {
restrictExchanges: {
@@ -510,7 +514,7 @@ export async function reportInsufficientBalanceDetails(
],
auditors: [],
},
- restrictWireMethods: req.wireMethod ? [req.wireMethod] : [],
+ restrictWireMethods: req.wireMethod ? [req.wireMethod] : undefined,
currency: Amounts.currencyOf(req.instructedAmount),
minAge: req.requiredMinimumAge ?? 0,
depositPaytoUri: req.depositPaytoUri,