gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: handle kyc error on invoice a


From: gnunet
Subject: [taler-wallet-core] branch master updated: handle kyc error on invoice and transfer
Date: Wed, 29 Mar 2023 05:06:44 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new efbde0e16 handle kyc error on invoice and transfer
efbde0e16 is described below

commit efbde0e16033542ae104f5365be5cee6e65ef7b0
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Mar 29 00:06:24 2023 -0300

    handle kyc error on invoice and transfer
---
 packages/taler-util/src/notifications.ts           |   8 +-
 packages/taler-wallet-core/src/db.ts               |   6 ++
 .../taler-wallet-core/src/operations/pay-peer.ts   | 103 ++++++++++++++++++++-
 .../taler-wallet-core/src/operations/withdraw.ts   |  41 ++++----
 .../src/wallet/DeveloperPage.tsx                   |  21 +++--
 .../src/wallet/Transaction.tsx                     |  15 +--
 6 files changed, 155 insertions(+), 39 deletions(-)

diff --git a/packages/taler-util/src/notifications.ts 
b/packages/taler-util/src/notifications.ts
index 51d573a98..0d85c85e9 100644
--- a/packages/taler-util/src/notifications.ts
+++ b/packages/taler-util/src/notifications.ts
@@ -62,7 +62,7 @@ export enum NotificationType {
   PendingOperationProcessed = "pending-operation-processed",
   ProposalRefused = "proposal-refused",
   ReserveRegisteredWithBank = "reserve-registered-with-bank",
-  WithdrawalGroupKycRequested = "withdrawal-group-kyc-requested",
+  KycRequested = "kyc-requested",
   WithdrawalGroupBankConfirmed = "withdrawal-group-bank-confirmed",
   WithdrawalGroupReserveReady = "withdrawal-group-reserve-ready",
   PeerPullCreditReady = "peer-pull-credit-ready",
@@ -125,8 +125,8 @@ export interface RefreshMeltedNotification {
   type: NotificationType.RefreshMelted;
 }
 
-export interface WithdrawalGroupKycRequested {
-  type: NotificationType.WithdrawalGroupKycRequested;
+export interface KycRequestedNotification {
+  type: NotificationType.KycRequested;
   transactionId: string;
   kycUrl: string;
 }
@@ -324,7 +324,7 @@ export type WalletNotification =
   | ReserveRegisteredWithBankNotification
   | ReserveNotYetFoundNotification
   | PayOperationSuccessNotification
-  | WithdrawalGroupKycRequested
+  | KycRequestedNotification
   | WithdrawalGroupBankConfirmed
   | WithdrawalGroupReserveReadyNotification
   | PeerPullCreditReadyNotification;
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index a7bdda3ec..cd676b7ca 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -1781,6 +1781,7 @@ export enum PeerPullPaymentInitiationStatus {
    * invoice and deposit money into it.
    */
   PurseCreated = 11 /* ACTIVE_START + 1 */,
+  KycRequired = 12 /* ACTIVE_START + 2 */,
   PurseDeposited = 50 /* DORMANT_START */,
 }
 
@@ -1831,12 +1832,15 @@ export interface PeerPullPaymentInitiationRecord {
    */
   status: PeerPullPaymentInitiationStatus;
 
+  kycInfo?: KycPendingInfo;
+
   withdrawalGroupId: string | undefined;
 }
 
 export enum PeerPushPaymentIncomingStatus {
   Proposed = 30 /* USER_ATTENTION_START */,
   Accepted = 10 /* ACTIVE_START */,
+  KycRequired = 11 /* ACTIVE_START + 1 */,
   /**
    * Merge was successful and withdrawal group has been created, now
    * everything is in the hand of the withdrawal group.
@@ -1887,6 +1891,8 @@ export interface PeerPushPaymentIncomingRecord {
    * with older (ver_minor<4) DB versions.
    */
   currency: string | undefined;
+
+  kycInfo?: KycPendingInfo;
 }
 
 export enum PeerPullPaymentIncomingStatus {
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts 
b/packages/taler-wallet-core/src/operations/pay-peer.ts
index 73dd3bf2c..ff0e15c00 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -73,10 +73,15 @@ import {
   codecForTimestamp,
   CancellationToken,
   NotificationType,
+  HttpStatusCode,
+  codecForWalletKycUuid,
+  WalletKycUuid,
 } from "@gnu-taler/taler-util";
 import { SpendCoinDetails } from "../crypto/cryptoImplementation.js";
 import {
   DenominationRecord,
+  KycPendingInfo,
+  KycUserType,
   OperationStatus,
   PeerPullPaymentIncomingStatus,
   PeerPullPaymentInitiationRecord,
@@ -115,6 +120,7 @@ import { getPeerPaymentBalanceDetailsInTx } from 
"./balance.js";
 import { updateExchangeFromUrl } from "./exchanges.js";
 import { getTotalRefreshCost } from "./refresh.js";
 import {
+  checkWithdrawalKycStatus,
   getExchangeWithdrawalInfo,
   internalCreateWithdrawalGroup,
   processWithdrawalGroup,
@@ -866,6 +872,23 @@ export async function processPeerPushCredit(
 
   const amount = Amounts.parseOrThrow(contractTerms.amount);
 
+  if (
+    peerInc.status === PeerPushPaymentIncomingStatus.KycRequired &&
+    peerInc.kycInfo
+  ) {
+    const txId = makeTransactionId(
+      TransactionType.PeerPushCredit,
+      peerInc.peerPushPaymentIncomingId,
+    );
+    await checkWithdrawalKycStatus(
+      ws,
+      peerInc.exchangeBaseUrl,
+      txId,
+      peerInc.kycInfo,
+      "individual",
+    );
+  }
+
   const mergeReserveInfo = await getMergeReserveInfo(ws, {
     exchangeBaseUrl: peerInc.exchangeBaseUrl,
   });
@@ -902,10 +925,40 @@ export async function processPeerPushCredit(
     reserve_sig: sigRes.accountSig,
   };
 
-  const mergeHttpReq = await ws.http.postJson(mergePurseUrl.href, mergeReq);
+  const mergeHttpResp = await ws.http.postJson(mergePurseUrl.href, mergeReq);
+
+  if (mergeHttpResp.status === HttpStatusCode.UnavailableForLegalReasons) {
+    const respJson = await mergeHttpResp.json();
+    const kycPending = codecForWalletKycUuid().decode(respJson);
+    logger.info(`kyc uuid response: ${j2s(kycPending)}`);
+
+    await ws.db
+      .mktx((x) => [x.peerPushPaymentIncoming])
+      .runReadWrite(async (tx) => {
+        const peerInc = await tx.peerPushPaymentIncoming.get(
+          peerPushPaymentIncomingId,
+        );
+        if (!peerInc) {
+          return;
+        }
+        peerInc.kycInfo = {
+          paytoHash: kycPending.h_payto,
+          requirementRow: kycPending.requirement_row,
+        };
+        peerInc.status = PeerPushPaymentIncomingStatus.KycRequired;
+        await tx.peerPushPaymentIncoming.put(peerInc);
+      });
+    return {
+      type: OperationAttemptResultType.Pending,
+      result: undefined,
+    };
+  }
 
   logger.trace(`merge request: ${j2s(mergeReq)}`);
-  const res = await readSuccessResponseJsonOrThrow(mergeHttpReq, 
codecForAny());
+  const res = await readSuccessResponseJsonOrThrow(
+    mergeHttpResp,
+    codecForAny(),
+  );
   logger.trace(`merge response: ${j2s(res)}`);
 
   await internalCreateWithdrawalGroup(ws, {
@@ -932,7 +985,10 @@ export async function processPeerPushCredit(
       if (!peerInc) {
         return;
       }
-      if (peerInc.status === PeerPushPaymentIncomingStatus.Accepted) {
+      if (
+        peerInc.status === PeerPushPaymentIncomingStatus.Accepted ||
+        peerInc.status === PeerPushPaymentIncomingStatus.KycRequired
+      ) {
         peerInc.status = PeerPushPaymentIncomingStatus.WithdrawalCreated;
       }
       await tx.peerPushPaymentIncoming.put(peerInc);
@@ -1423,6 +1479,22 @@ export async function processPeerPullCredit(
       return {
         type: OperationAttemptResultType.Longpoll,
       };
+    case PeerPullPaymentInitiationStatus.KycRequired: {
+      if (pullIni.kycInfo) {
+        const txId = makeTransactionId(
+          TransactionType.PeerPullCredit,
+          pullIni.pursePub,
+        );
+        await checkWithdrawalKycStatus(
+          ws,
+          pullIni.exchangeBaseUrl,
+          txId,
+          pullIni.kycInfo,
+          "individual",
+        );
+      }
+      break;
+    }
     case PeerPullPaymentInitiationStatus.Initial:
       break;
     default:
@@ -1496,6 +1568,31 @@ export async function processPeerPullCredit(
     reservePurseReqBody,
   );
 
+  if (httpResp.status === HttpStatusCode.UnavailableForLegalReasons) {
+    const respJson = await httpResp.json();
+    const kycPending = codecForWalletKycUuid().decode(respJson);
+    logger.info(`kyc uuid response: ${j2s(kycPending)}`);
+
+    await ws.db
+      .mktx((x) => [x.peerPullPaymentInitiations])
+      .runReadWrite(async (tx) => {
+        const peerIni = await tx.peerPullPaymentInitiations.get(pursePub);
+        if (!peerIni) {
+          return;
+        }
+        peerIni.kycInfo = {
+          paytoHash: kycPending.h_payto,
+          requirementRow: kycPending.requirement_row,
+        };
+        peerIni.status = PeerPullPaymentInitiationStatus.KycRequired;
+        await tx.peerPullPaymentInitiations.put(peerIni);
+      });
+    return {
+      type: OperationAttemptResultType.Pending,
+      result: undefined,
+    };
+  }
+
   const resp = await readSuccessResponseJsonOrThrow(httpResp, codecForAny());
 
   logger.info(`reserve merge response: ${j2s(resp)}`);
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index 3c3878792..2c91d4184 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -116,9 +116,7 @@ import {
   WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
   WALLET_EXCHANGE_PROTOCOL_VERSION,
 } from "../versions.js";
-import {
-  makeTransactionId,
-} from "./common.js";
+import { makeTransactionId } from "./common.js";
 import {
   getExchangeDetails,
   getExchangePaytoUri,
@@ -1226,9 +1224,14 @@ export async function processWithdrawalGroup(
 
   if (numKycRequired > 0) {
     if (kycInfo) {
+      const txId = makeTransactionId(
+        TransactionType.Withdrawal,
+        withdrawalGroup.withdrawalGroupId,
+      );
       await checkWithdrawalKycStatus(
         ws,
-        withdrawalGroup,
+        withdrawalGroup.exchangeBaseUrl,
+        txId,
         kycInfo,
         "individual",
       );
@@ -1271,42 +1274,44 @@ export async function processWithdrawalGroup(
 
 export async function checkWithdrawalKycStatus(
   ws: InternalWalletState,
-  wg: WithdrawalGroupRecord,
+  exchangeUrl: string,
+  txId: string,
   kycInfo: KycPendingInfo,
   userType: KycUserType,
 ): Promise<void> {
-  const exchangeUrl = wg.exchangeBaseUrl;
   const url = new URL(
     `kyc-check/${kycInfo.requirementRow}/${kycInfo.paytoHash}/${userType}`,
     exchangeUrl,
   );
   logger.info(`kyc url ${url.href}`);
-  const kycStatusReq = await ws.http.fetch(url.href, {
+  const kycStatusRes = await ws.http.fetch(url.href, {
     method: "GET",
   });
-  if (kycStatusReq.status === HttpStatusCode.Ok) {
+  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
+  ) {
     logger.warn("kyc requested, but already fulfilled");
     return;
-  } else if (kycStatusReq.status === HttpStatusCode.Accepted) {
-    const kycStatus = await kycStatusReq.json();
+  } else if (kycStatusRes.status === HttpStatusCode.Accepted) {
+    const kycStatus = await kycStatusRes.json();
     logger.info(`kyc status: ${j2s(kycStatus)}`);
     ws.notify({
-      type: NotificationType.WithdrawalGroupKycRequested,
+      type: NotificationType.KycRequested,
       kycUrl: kycStatus.kyc_url,
-      transactionId: makeTransactionId(
-        TransactionType.Withdrawal,
-        wg.withdrawalGroupId,
-      ),
+      transactionId: txId,
     });
     throw TalerError.fromDetail(
-      TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED,
+      TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED, //FIXME: another error 
code or rename for merge
       {
         kycUrl: kycStatus.kyc_url,
       },
-      `KYC check required for withdrawal`,
+      `KYC check required for transfer`,
     );
   } else {
-    throw Error(`unexpected response from kyc-check (${kycStatusReq.status})`);
+    throw Error(`unexpected response from kyc-check (${kycStatusRes.status})`);
   }
 }
 
diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
index 2db2041d4..339e69213 100644
--- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
@@ -140,12 +140,19 @@ export function View({
     });
   }
   const api = useBackendContext();
+
   const fileRef = useRef<HTMLInputElement>(null);
   async function onImportDatabase(str: string): Promise<void> {
     return api.wallet.call(WalletApiOperation.ImportDb, {
       dump: JSON.parse(str),
     });
   }
+
+  const hook = useAsyncAsHook(() =>
+    api.wallet.call(WalletApiOperation.ListExchanges, {}),
+  );
+  const exchangeList = hook && !hook.hasError ? hook.response.exchanges : [];
+
   const currencies: { [ex: string]: string } = {};
   const money_by_exchange = coins.reduce(
     (prev, cur) => {
@@ -171,7 +178,6 @@ export function View({
       [exchange_name: string]: CalculatedCoinfInfo[];
     },
   );
-  const exchanges = Object.keys(money_by_exchange);
 
   const [tagName, setTagName] = useState("");
   const [logLevel, setLogLevel] = useState("info");
@@ -324,27 +330,28 @@ export function View({
             variant="contained"
             onClick={async () => {
               const result = await Promise.all(
-                exchanges.map(async (ex) => {
+                exchangeList.map(async (exchange) => {
+                  const url = exchange.exchangeBaseUrl;
                   const oldKeys = JSON.stringify(
-                    await (await fetch(`${ex}keys`)).json(),
+                    await (await fetch(`${url}keys`)).json(),
                   );
                   const oldWire = JSON.stringify(
-                    await (await fetch(`${ex}wire`)).json(),
+                    await (await fetch(`${url}wire`)).json(),
                   );
                   const newKeys = JSON.stringify(
                     await (
-                      await fetch(`${ex}keys`, { cache: "no-cache" })
+                      await fetch(`${url}keys`, { cache: "no-cache" })
                     ).json(),
                   );
                   const newWire = JSON.stringify(
                     await (
-                      await fetch(`${ex}wire`, { cache: "no-cache" })
+                      await fetch(`${url}wire`, { cache: "no-cache" })
                     ).json(),
                   );
                   return oldKeys !== newKeys || newWire !== oldWire;
                 }),
               );
-              const ex = exchanges.filter((e, i) => result[i]);
+              const ex = exchangeList.filter((e, i) => result[i]);
               if (!ex.length) {
                 alert("no exchange was outdated");
               } else {
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx 
b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index b9b1aa198..217a77575 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -879,13 +879,14 @@ export function TransactionView({
           kind="neutral"
         />
         {transaction.extendedStatus ===
-          ExtendedStatus.Pending /** pending is not-pay */ && (
-          <Part
-            title={i18n.str`URI`}
-            text={<ShowQrWithCopy text={transaction.talerUri} />}
-            kind="neutral"
-          />
-        )}
+          ExtendedStatus.Pending /** pending is not-pay */ &&
+          !transaction.error && (
+            <Part
+              title={i18n.str`URI`}
+              text={<ShowQrWithCopy text={transaction.talerUri} />}
+              kind="neutral"
+            />
+          )}
         <Part
           title={i18n.str`Details`}
           text={

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]