aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-09-05 21:15:22 +0200
committerFlorian Dold <florian@dold.me>2024-09-05 21:15:22 +0200
commit5402b00b796011005f52e200c856832f225ffaf9 (patch)
tree5836ea9f7ebd72921bbd9f7ad4a725205c6e3003
parent0f9ff6e37fe45e2f2e4db95a517a35a3df5cea6e (diff)
downloadwallet-core-5402b00b796011005f52e200c856832f225ffaf9.tar.xz
wallet-core: support KYC directly on deposit in deposit tx, test
-rw-r--r--packages/taler-harness/src/integrationtests/test-kyc-deposit-deposit.ts295
-rw-r--r--packages/taler-harness/src/integrationtests/testrunner.ts2
-rw-r--r--packages/taler-wallet-core/src/balance.ts8
-rw-r--r--packages/taler-wallet-core/src/db.ts13
-rw-r--r--packages/taler-wallet-core/src/deposits.ts144
-rw-r--r--packages/taler-wallet-core/src/pay-peer-push-credit.ts7
6 files changed, 423 insertions, 46 deletions
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-deposit-deposit.ts b/packages/taler-harness/src/integrationtests/test-kyc-deposit-deposit.ts
new file mode 100644
index 000000000..2ee58c7d8
--- /dev/null
+++ b/packages/taler-harness/src/integrationtests/test-kyc-deposit-deposit.ts
@@ -0,0 +1,295 @@
+/*
+ This file is part of GNU Taler
+ (C) 2020 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Imports.
+ */
+import {
+ TalerCorebankApiClient,
+ TransactionMajorState,
+ TransactionMinorState,
+} from "@gnu-taler/taler-util";
+import {
+ createSyncCryptoApi,
+ EddsaKeypairStrings,
+ WalletApiOperation,
+} from "@gnu-taler/taler-wallet-core";
+import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
+import {
+ BankService,
+ DbInfo,
+ ExchangeService,
+ generateRandomPayto,
+ GlobalTestState,
+ HarnessExchangeBankAccount,
+ setupDb,
+ WalletClient,
+ WalletService,
+} from "../harness/harness.js";
+import {
+ EnvOptions,
+ postAmlDecisionNoRules,
+ withdrawViaBankV3,
+} from "../harness/helpers.js";
+
+interface KycTestEnv {
+ commonDb: DbInfo;
+ bankClient: TalerCorebankApiClient;
+ exchange: ExchangeService;
+ exchangeBankAccount: HarnessExchangeBankAccount;
+ walletClient: WalletClient;
+ walletService: WalletService;
+ amlKeypair: EddsaKeypairStrings;
+}
+
+async function createKycTestkudosEnvironment(
+ t: GlobalTestState,
+ coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => x("TESTKUDOS")),
+ opts: EnvOptions = {},
+): Promise<KycTestEnv> {
+ const db = await setupDb(t);
+
+ const bank = await BankService.create(t, {
+ allowRegistrations: true,
+ currency: "TESTKUDOS",
+ database: db.connStr,
+ httpPort: 8082,
+ });
+
+ const exchange = ExchangeService.create(t, {
+ name: "testexchange-1",
+ currency: "TESTKUDOS",
+ httpPort: 8081,
+ database: db.connStr,
+ });
+
+ let receiverName = "Exchange";
+ let exchangeBankUsername = "exchange";
+ let exchangeBankPassword = "mypw";
+ let exchangePaytoUri = generateRandomPayto(exchangeBankUsername);
+
+ await exchange.addBankAccount("1", {
+ accountName: exchangeBankUsername,
+ accountPassword: exchangeBankPassword,
+ wireGatewayApiBaseUrl: new URL(
+ "accounts/exchange/taler-wire-gateway/",
+ bank.baseUrl,
+ ).href,
+ accountPaytoUri: exchangePaytoUri,
+ });
+
+ bank.setSuggestedExchange(exchange, exchangePaytoUri);
+
+ await bank.start();
+
+ await bank.pingUntilAvailable();
+
+ const bankClient = new TalerCorebankApiClient(bank.corebankApiBaseUrl, {
+ auth: {
+ username: "admin",
+ password: "adminpw",
+ },
+ });
+
+ await bankClient.registerAccountExtended({
+ name: receiverName,
+ password: exchangeBankPassword,
+ username: exchangeBankUsername,
+ is_taler_exchange: true,
+ payto_uri: exchangePaytoUri,
+ });
+
+ const ageMaskSpec = opts.ageMaskSpec;
+
+ if (ageMaskSpec) {
+ exchange.enableAgeRestrictions(ageMaskSpec);
+ // Enable age restriction for all coins.
+ exchange.addCoinConfigList(
+ coinConfig.map((x) => ({
+ ...x,
+ name: `${x.name}-age`,
+ ageRestricted: true,
+ })),
+ );
+ // For mixed age restrictions, we also offer coins without age restrictions
+ if (opts.mixedAgeRestriction) {
+ exchange.addCoinConfigList(
+ coinConfig.map((x) => ({ ...x, ageRestricted: false })),
+ );
+ }
+ } else {
+ exchange.addCoinConfigList(coinConfig);
+ }
+
+ await exchange.modifyConfig(async (config) => {
+ config.setString("exchange", "enable_kyc", "yes");
+
+ config.setString("KYC-RULE-R1", "operation_type", "deposit");
+ config.setString("KYC-RULE-R1", "enabled", "yes");
+ config.setString("KYC-RULE-R1", "exposed", "yes");
+ config.setString("KYC-RULE-R1", "is_and_combinator", "yes");
+ config.setString("KYC-RULE-R1", "threshold", "TESTKUDOS:5");
+ config.setString("KYC-RULE-R1", "timeframe", "1d");
+ config.setString("KYC-RULE-R1", "next_measures", "M1");
+
+ config.setString("KYC-MEASURE-M1", "check_name", "C1");
+ config.setString("KYC-MEASURE-M1", "context", "{}");
+ config.setString("KYC-MEASURE-M1", "program", "P1");
+
+ config.setString("AML-PROGRAM-P1", "command", "/bin/true");
+ config.setString("AML-PROGRAM-P1", "enabled", "true");
+ config.setString("AML-PROGRAM-P1", "description", "this does nothing");
+ config.setString("AML-PROGRAM-P1", "fallback", "M1");
+
+ config.setString("KYC-CHECK-C1", "type", "INFO");
+ config.setString("KYC-CHECK-C1", "description", "my check!");
+ config.setString("KYC-CHECK-C1", "fallback", "M1");
+ });
+
+ await exchange.start();
+
+ const cryptoApi = createSyncCryptoApi();
+ const amlKeypair = await cryptoApi.createEddsaKeypair({});
+
+ await exchange.enableAmlAccount(amlKeypair.pub, "Alice");
+
+ const walletService = new WalletService(t, {
+ name: "wallet",
+ useInMemoryDb: true,
+ });
+ await walletService.start();
+ await walletService.pingUntilAvailable();
+
+ const walletClient = new WalletClient({
+ name: "wallet",
+ unixPath: walletService.socketPath,
+ onNotification(n) {
+ console.log("got notification", n);
+ },
+ });
+ await walletClient.connect();
+ await walletClient.client.call(WalletApiOperation.InitWallet, {
+ config: {
+ testing: {
+ skipDefaults: true,
+ },
+ },
+ });
+
+ console.log("setup done!");
+
+ return {
+ commonDb: db,
+ exchange,
+ amlKeypair,
+ walletClient,
+ walletService,
+ bankClient,
+ exchangeBankAccount: {
+ accountName: "",
+ accountPassword: "",
+ accountPaytoUri: "",
+ wireGatewayApiBaseUrl: "",
+ },
+ };
+}
+
+export async function runKycDepositDepositTest(t: GlobalTestState) {
+ // Set up test environment
+
+ const { walletClient, bankClient, exchange, amlKeypair } =
+ await createKycTestkudosEnvironment(t);
+
+ // Withdraw digital cash into the wallet.
+
+ const wres = await withdrawViaBankV3(t, {
+ bankClient,
+ amount: "TESTKUDOS:50",
+ exchange: exchange,
+ walletClient: walletClient,
+ });
+
+ await wres.withdrawalFinishedCond;
+
+ const depositResp = await walletClient.call(
+ WalletApiOperation.CreateDepositGroup,
+ {
+ amount: "TESTKUDOS:10",
+ depositPaytoUri: wres.accountPaytoUri,
+ },
+ );
+
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: depositResp.transactionId,
+ txState: {
+ major: TransactionMajorState.Pending,
+ minor: TransactionMinorState.Track,
+ },
+ });
+
+ await exchange.runAggregatorOnceWithTimetravel({
+ timetravelMicroseconds: 1000 * 1000 * 60 * 60 * 3,
+ });
+
+ await exchange.runTransferOnceWithTimetravel({
+ timetravelMicroseconds: 1000 * 1000 * 60 * 60 * 3,
+ });
+
+ console.log("waiting for kyc-required");
+
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: depositResp.transactionId,
+ txState: {
+ major: TransactionMajorState.Pending,
+ minor: TransactionMinorState.KycRequired,
+ },
+ });
+
+ const txDetails = await walletClient.call(
+ WalletApiOperation.GetTransactionById,
+ {
+ transactionId: depositResp.transactionId,
+ },
+ );
+
+ const kycPaytoHash = txDetails.kycPaytoHash;
+
+ t.assertTrue(!!kycPaytoHash);
+
+ await postAmlDecisionNoRules(t, {
+ amlPriv: amlKeypair.priv,
+ amlPub: amlKeypair.pub,
+ exchangeBaseUrl: exchange.baseUrl,
+ paytoHash: kycPaytoHash,
+ });
+
+ await exchange.runAggregatorOnceWithTimetravel({
+ timetravelMicroseconds: 1000 * 1000 * 60 * 60 * 3,
+ });
+
+ await exchange.runTransferOnceWithTimetravel({
+ timetravelMicroseconds: 1000 * 1000 * 60 * 60 * 3,
+ });
+
+ await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
+ transactionId: depositResp.transactionId,
+ txState: {
+ major: TransactionMajorState.Done,
+ },
+ });
+}
+
+runKycDepositDepositTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
index f7ae50149..32bac3fdc 100644
--- a/packages/taler-harness/src/integrationtests/testrunner.ts
+++ b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -49,6 +49,7 @@ import { runFeeRegressionTest } from "./test-fee-regression.js";
import { runForcedSelectionTest } from "./test-forced-selection.js";
import { runKycBalanceWithdrawalTest } from "./test-kyc-balance-withdrawal.js";
import { runKycDepositAggregateTest } from "./test-kyc-deposit-aggregate.js";
+import { runKycDepositDepositTest } from "./test-kyc-deposit-deposit.js";
import { runKycExchangeWalletTest } from "./test-kyc-exchange-wallet.js";
import { runKycFormWithdrawalTest } from "./test-kyc-form-withdrawal.js";
import { runKycNewMeasureTest } from "./test-kyc-new-measure.js";
@@ -260,6 +261,7 @@ const allTests: TestMainFunction[] = [
runKycFormWithdrawalTest,
runKycBalanceWithdrawalTest,
runKycNewMeasureTest,
+ runKycDepositDepositTest,
];
export interface TestRunSpec {
diff --git a/packages/taler-wallet-core/src/balance.ts b/packages/taler-wallet-core/src/balance.ts
index 396efda1f..99979f59a 100644
--- a/packages/taler-wallet-core/src/balance.ts
+++ b/packages/taler-wallet-core/src/balance.ts
@@ -449,14 +449,14 @@ export async function getBalancesInsideTransaction(
for (const [e, x] of Object.entries(perExchange)) {
const currency = Amounts.currencyOf(dgRecord.amount);
switch (dgRecord.operationStatus) {
- case DepositOperationStatus.SuspendedKyc:
- case DepositOperationStatus.PendingKyc:
+ case DepositOperationStatus.SuspendedAggregateKyc:
+ case DepositOperationStatus.PendingAggregateKyc:
await balanceStore.setFlagOutgoingKyc(currency, e);
}
switch (dgRecord.operationStatus) {
- case DepositOperationStatus.SuspendedKyc:
- case DepositOperationStatus.PendingKyc:
+ case DepositOperationStatus.SuspendedAggregateKyc:
+ case DepositOperationStatus.PendingAggregateKyc:
case DepositOperationStatus.PendingTrack:
case DepositOperationStatus.SuspendedAborting:
case DepositOperationStatus.SuspendedDeposit:
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 99b69135a..ba33c5555 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1725,15 +1725,18 @@ export interface BackupProviderRecord {
export enum DepositOperationStatus {
PendingDeposit = 0x0100_0000,
+ SuspendedDeposit = 0x0110_0000,
+
PendingTrack = 0x0100_0001,
- PendingKyc = 0x0100_0002,
+ SuspendedTrack = 0x0110_0001,
- Aborting = 0x0103_0000,
+ PendingAggregateKyc = 0x0100_0002,
+ SuspendedAggregateKyc = 0x0110_0002,
- SuspendedDeposit = 0x0110_0000,
- SuspendedTrack = 0x0110_0001,
- SuspendedKyc = 0x0110_0002,
+ PendingDepositKyc = 0x0100_0003,
+ SuspendedDepositKyc = 0x0110_0003,
+ Aborting = 0x0103_0000,
SuspendedAborting = 0x0113_0000,
Finished = 0x0500_0000,
diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts
index da69530f7..371d7cf70 100644
--- a/packages/taler-wallet-core/src/deposits.ts
+++ b/packages/taler-wallet-core/src/deposits.ts
@@ -63,6 +63,7 @@ import {
checkLogicInvariant,
codecForAccountKycStatus,
codecForBatchDepositSuccess,
+ codecForLegitimizationNeededResponse,
codecForTackTransactionAccepted,
codecForTackTransactionWired,
encodeCrock,
@@ -94,7 +95,6 @@ import {
DepositElementStatus,
DepositGroupRecord,
DepositInfoPerExchange,
- DepositKycInfo,
DepositOperationStatus,
DepositTrackingInfo,
RefreshOperationStatus,
@@ -293,11 +293,23 @@ export class DepositTransactionContext implements TransactionContext {
const oldState = computeDepositTransactionStatus(dg);
let newOpStatus: DepositOperationStatus | undefined;
switch (dg.operationStatus) {
+ case DepositOperationStatus.Aborted:
+ case DepositOperationStatus.Failed:
+ case DepositOperationStatus.Finished:
+ case DepositOperationStatus.SuspendedAborting:
+ case DepositOperationStatus.SuspendedAggregateKyc:
+ case DepositOperationStatus.SuspendedDeposit:
+ case DepositOperationStatus.SuspendedDepositKyc:
+ case DepositOperationStatus.SuspendedTrack:
+ break;
+ case DepositOperationStatus.PendingDepositKyc:
+ newOpStatus = DepositOperationStatus.SuspendedDepositKyc;
+ break;
case DepositOperationStatus.PendingDeposit:
newOpStatus = DepositOperationStatus.SuspendedDeposit;
break;
- case DepositOperationStatus.PendingKyc:
- newOpStatus = DepositOperationStatus.SuspendedKyc;
+ case DepositOperationStatus.PendingAggregateKyc:
+ newOpStatus = DepositOperationStatus.SuspendedAggregateKyc;
break;
case DepositOperationStatus.PendingTrack:
newOpStatus = DepositOperationStatus.SuspendedTrack;
@@ -305,6 +317,8 @@ export class DepositTransactionContext implements TransactionContext {
case DepositOperationStatus.Aborting:
newOpStatus = DepositOperationStatus.SuspendedAborting;
break;
+ default:
+ assertUnreachable(dg.operationStatus);
}
if (!newOpStatus) {
return undefined;
@@ -376,18 +390,32 @@ export class DepositTransactionContext implements TransactionContext {
const oldState = computeDepositTransactionStatus(dg);
let newOpStatus: DepositOperationStatus | undefined;
switch (dg.operationStatus) {
+ case DepositOperationStatus.Aborted:
+ case DepositOperationStatus.Aborting:
+ case DepositOperationStatus.Failed:
+ case DepositOperationStatus.Finished:
+ case DepositOperationStatus.PendingAggregateKyc:
+ case DepositOperationStatus.PendingDeposit:
+ case DepositOperationStatus.PendingDepositKyc:
+ case DepositOperationStatus.PendingTrack:
+ break;
+ case DepositOperationStatus.SuspendedDepositKyc:
+ newOpStatus = DepositOperationStatus.PendingDepositKyc;
+ break;
case DepositOperationStatus.SuspendedDeposit:
newOpStatus = DepositOperationStatus.PendingDeposit;
break;
case DepositOperationStatus.SuspendedAborting:
newOpStatus = DepositOperationStatus.Aborting;
break;
- case DepositOperationStatus.SuspendedKyc:
- newOpStatus = DepositOperationStatus.PendingKyc;
+ case DepositOperationStatus.SuspendedAggregateKyc:
+ newOpStatus = DepositOperationStatus.PendingAggregateKyc;
break;
case DepositOperationStatus.SuspendedTrack:
newOpStatus = DepositOperationStatus.PendingTrack;
break;
+ default:
+ assertUnreachable(dg.operationStatus);
}
if (!newOpStatus) {
return undefined;
@@ -459,7 +487,7 @@ export function computeDepositTransactionStatus(
major: TransactionMajorState.Pending,
minor: TransactionMinorState.Deposit,
};
- case DepositOperationStatus.PendingKyc:
+ case DepositOperationStatus.PendingAggregateKyc:
return {
major: TransactionMajorState.Pending,
minor: TransactionMinorState.KycRequired,
@@ -469,7 +497,7 @@ export function computeDepositTransactionStatus(
major: TransactionMajorState.Pending,
minor: TransactionMinorState.Track,
};
- case DepositOperationStatus.SuspendedKyc:
+ case DepositOperationStatus.SuspendedAggregateKyc:
return {
major: TransactionMajorState.Suspended,
minor: TransactionMinorState.KycRequired,
@@ -499,6 +527,18 @@ export function computeDepositTransactionStatus(
return {
major: TransactionMajorState.SuspendedAborting,
};
+ case DepositOperationStatus.PendingDepositKyc:
+ return {
+ major: TransactionMajorState.Pending,
+ // We lie to the UI by hiding the specific KYC state.
+ minor: TransactionMinorState.KycRequired,
+ };
+ case DepositOperationStatus.SuspendedDepositKyc:
+ return {
+ major: TransactionMajorState.Suspended,
+ // We lie to the UI by hiding the specific KYC state.
+ minor: TransactionMinorState.KycRequired,
+ };
default:
assertUnreachable(dg.operationStatus);
}
@@ -534,7 +574,7 @@ export function computeDepositTransactionActions(
return [TransactionAction.Delete];
case DepositOperationStatus.SuspendedAborting:
return [TransactionAction.Resume, TransactionAction.Fail];
- case DepositOperationStatus.PendingKyc:
+ case DepositOperationStatus.PendingAggregateKyc:
return [
TransactionAction.Retry,
TransactionAction.Suspend,
@@ -546,10 +586,14 @@ export function computeDepositTransactionActions(
TransactionAction.Suspend,
TransactionAction.Abort,
];
- case DepositOperationStatus.SuspendedKyc:
+ case DepositOperationStatus.SuspendedAggregateKyc:
return [TransactionAction.Resume, TransactionAction.Fail];
case DepositOperationStatus.SuspendedTrack:
return [TransactionAction.Resume, TransactionAction.Abort];
+ case DepositOperationStatus.PendingDepositKyc:
+ return [TransactionAction.Resume, TransactionAction.Abort];
+ case DepositOperationStatus.SuspendedDepositKyc:
+ return [TransactionAction.Suspend, TransactionAction.Abort];
default:
assertUnreachable(dg.operationStatus);
}
@@ -778,6 +822,10 @@ async function processDepositGroupAborting(
return waitForRefreshOnDepositGroup(wex, depositGroup);
}
+/**
+ * Process the transaction in states where KYC is required.
+ * Used for both the deposit KYC and aggregate KYC.
+ */
async function processDepositGroupPendingKyc(
wex: WalletExecutionContext,
depositGroup: DepositGroupRecord,
@@ -832,8 +880,6 @@ async function processDepositGroupPendingKyc(
if (
kycStatusRes.status === HttpStatusCode.Ok ||
- //FIXME: NoContent is not expected https://docs.taler.net/core/api-exchange.html#post--purses-$PURSE_PUB-merge
- // remove after the exchange is fixed or clarified
kycStatusRes.status === HttpStatusCode.NoContent
) {
const transitionInfo = await wex.db.runReadWriteTx(
@@ -843,20 +889,26 @@ async function processDepositGroupPendingKyc(
if (!newDg) {
return;
}
- if (newDg.operationStatus !== DepositOperationStatus.PendingKyc) {
- return;
- }
const oldTxState = computeDepositTransactionStatus(newDg);
- newDg.operationStatus = DepositOperationStatus.PendingTrack;
- const newTxState = computeDepositTransactionStatus(newDg);
+ switch (newDg.operationStatus) {
+ case DepositOperationStatus.PendingAggregateKyc:
+ newDg.operationStatus = DepositOperationStatus.PendingTrack;
+ break;
+ case DepositOperationStatus.PendingDeposit:
+ newDg.operationStatus = DepositOperationStatus.PendingDeposit;
+ break;
+ default:
+ return;
+ }
await tx.depositGroups.put(newDg);
await ctx.updateTransactionMeta(tx);
+ const newTxState = computeDepositTransactionStatus(newDg);
return { oldTxState, newTxState };
},
);
notifyTransition(wex, transactionId, transitionInfo);
} else if (kycStatusRes.status === HttpStatusCode.Accepted) {
- // FIXME: Do we have to update the URL here?
+ logger.info("kyc still pending");
} else {
throw Error(`unexpected response from kyc-check (${kycStatusRes.status})`);
}
@@ -907,7 +959,7 @@ async function getLastWithdrawalKeyPair(
async function transitionToKycRequired(
wex: WalletExecutionContext,
depositGroup: DepositGroupRecord,
- kycInfo: DepositKycInfo,
+ kycPaytoHash: string,
exchangeUrl: string,
): Promise<TaskRunResult> {
const { depositGroupId } = depositGroup;
@@ -924,7 +976,7 @@ async function transitionToKycRequired(
accountPub: lastReserveKeypair.pub,
});
- const url = new URL(`kyc-check/${kycInfo.paytoHash}`, exchangeUrl);
+ const url = new URL(`kyc-check/${kycPaytoHash}`, exchangeUrl);
logger.info(`kyc url ${url.href}`);
const kycStatusResp = await wex.http.fetch(url.href, {
method: "GET",
@@ -948,14 +1000,20 @@ async function transitionToKycRequired(
if (!dg) {
return undefined;
}
- if (dg.operationStatus !== DepositOperationStatus.PendingTrack) {
- return undefined;
- }
const oldTxState = computeDepositTransactionStatus(dg);
- dg.operationStatus = DepositOperationStatus.PendingKyc;
+ switch (dg.operationStatus) {
+ case DepositOperationStatus.PendingTrack:
+ dg.operationStatus = DepositOperationStatus.PendingAggregateKyc;
+ break;
+ case DepositOperationStatus.PendingDeposit:
+ dg.operationStatus = DepositOperationStatus.PendingDepositKyc;
+ break;
+ default:
+ return;
+ }
dg.kycInfo = {
exchangeBaseUrl: exchangeUrl,
- paytoHash: kycInfo.paytoHash,
+ paytoHash: kycPaytoHash,
accessToken: statusResp.access_token,
};
await tx.depositGroups.put(dg);
@@ -1026,15 +1084,10 @@ async function processDepositGroupPendingTrack(
const paytoHash = encodeCrock(
hashTruncate32(stringToBytes(depositGroup.wire.payto_uri + "\0")),
);
- const kycInfo: DepositKycInfo = {
- paytoHash,
- exchangeBaseUrl: exchangeBaseUrl,
- accessToken: undefined,
- };
return transitionToKycRequired(
wex,
depositGroup,
- kycInfo,
+ paytoHash,
exchangeBaseUrl,
);
} else {
@@ -1292,7 +1345,7 @@ async function processDepositGroupPendingDeposit(
}
// We need to do one batch per exchange.
- for (const exchangeUrl of exchanges.values()) {
+ for (const exchangeBaseUrl of exchanges.values()) {
const coins: BatchDepositRequestCoin[] = [];
const batchIndexes: number[] = [];
@@ -1309,7 +1362,7 @@ async function processDepositGroupPendingDeposit(
for (let i = 0; i < depositPermissions.length; i++) {
const perm = depositPermissions[i];
- if (perm.exchange_url != exchangeUrl) {
+ if (perm.exchange_url != exchangeBaseUrl) {
continue;
}
coins.push({
@@ -1325,7 +1378,7 @@ async function processDepositGroupPendingDeposit(
// Check for cancellation before making network request.
cancellationToken?.throwIfCancelled();
- const url = new URL(`batch-deposit`, exchangeUrl);
+ const url = new URL(`batch-deposit`, exchangeBaseUrl);
logger.info(`depositing to ${url.href}`);
logger.trace(`deposit request: ${j2s(batchReq)}`);
const httpResp = await wex.http.fetch(url.href, {
@@ -1333,6 +1386,28 @@ async function processDepositGroupPendingDeposit(
body: batchReq,
cancellationToken: cancellationToken,
});
+
+ switch (httpResp.status) {
+ case HttpStatusCode.Accepted:
+ case HttpStatusCode.Ok:
+ break;
+ case HttpStatusCode.UnavailableForLegalReasons: {
+ const kycLegiNeededResp = await readResponseJsonOrThrow(
+ httpResp,
+ codecForLegitimizationNeededResponse(),
+ );
+ logger.info(
+ `kyc legitimization needed response: ${j2s(kycLegiNeededResp)}`,
+ );
+ return transitionToKycRequired(
+ wex,
+ depositGroup,
+ kycLegiNeededResp.h_payto,
+ exchangeBaseUrl,
+ );
+ }
+ }
+
await readSuccessResponseJsonOrThrow(
httpResp,
codecForBatchDepositSuccess(),
@@ -1406,7 +1481,8 @@ export async function processDepositGroup(
switch (depositGroup.operationStatus) {
case DepositOperationStatus.PendingTrack:
return processDepositGroupPendingTrack(wex, depositGroup);
- case DepositOperationStatus.PendingKyc:
+ case DepositOperationStatus.PendingAggregateKyc:
+ case DepositOperationStatus.PendingDepositKyc:
return processDepositGroupPendingKyc(wex, depositGroup);
case DepositOperationStatus.PendingDeposit:
return processDepositGroupPendingDeposit(wex, depositGroup);
diff --git a/packages/taler-wallet-core/src/pay-peer-push-credit.ts b/packages/taler-wallet-core/src/pay-peer-push-credit.ts
index fd6d40bcf..865e7e6a3 100644
--- a/packages/taler-wallet-core/src/pay-peer-push-credit.ts
+++ b/packages/taler-wallet-core/src/pay-peer-push-credit.ts
@@ -986,9 +986,10 @@ async function handlePendingMerge(
});
if (mergeHttpResp.status === HttpStatusCode.UnavailableForLegalReasons) {
- const respJson = await mergeHttpResp.json();
- const kycLegiNeededResp =
- codecForLegitimizationNeededResponse().decode(respJson);
+ const kycLegiNeededResp = await readResponseJsonOrThrow(
+ mergeHttpResp,
+ codecForLegitimizationNeededResponse(),
+ );
logger.info(
`kyc legitimization needed response: ${j2s(kycLegiNeededResp)}`,
);