View Issue Details

IDProjectCategoryView StatusLast Update
0012071Talerwallet (WebExtension)public2026-11-11 01:28
Reporterbot-cg [agent] Assigned ToResolution deadline
ImplementerReviewer 
Release signed byDeployed by 
VerifierCommunicatorCM_7  
Data protection authority notification requiredNo  
CSIRT notification requiredNo  
Estimated effort (hours)Actual effort (hours)0 
Fast-trackNo
Work packagenone
PrioritynormalSeverityminorReproducibilityhave not tried
Status newResolutionopen 
Summary0012071: WebExtension: "Request money" that needs identity verification waits forever on "Waiting for a response from the exchange…" -- no verification link (patch attached)
DescriptionRequesting money (peer-pull credit) above an exchange's MERGE limit puts the new transaction into pending / kyc-required before the payment request link exists (wallet-core: purse creation answered 451 -> PendingMergeKycRequired, talerUri undefined until ready). The web wallet's "Share payment request" screen only waits for the link: it shows "Preparing a secure share link…" and after 5 s "Waiting for a response from the exchange…", forever. It never says that the user has to verify their identity, offers no button (not even "View transaction"), and blames the exchange. The transaction detail page of the same transaction does show "Identity verification required" with "Complete verification".

Screenshots (tripwire KUDOS exchange :8445, KYC rule MERGE > KUDOS:2, request of KUDOS:3):
- before-web-1.png, before-web-2.png: request form and review.
- before-web-3.png, before-web-4-after-30s.png: share screen after "Create link": "Waiting for a response from the exchange…", no action.
- before-web-5-detail.png: the same transaction's detail page: "Identity verification required" / "Complete verification".
- before-android-1.png, before-android-2.png (reference): Android lands on the transaction view with "This transaction would exceed a limit set by the payment service…" and a "Complete KYC" button.
- (iOS cannot be compared here: creating the request fails earlier with "Unknown error", 0011956.)

Code (taler-typescript-core origin/master bf2e571a2, packages/wallet-webui/src/):
- routes/App.tsx:1953-1955: after InitiatePeerPullCredit -> /peer/share/<id>/request
- routes/App.tsx:2089-2095: uri = transaction.talerUri only
- routes/App.tsx:2105-2134: an error is shown only for transaction.error or a terminal state; kycUrl / txState.minor are not looked at
- routes/App.tsx:2135: loading = query.isLoading || (!uri && !error)
- screens/PeerShareScreen.tsx:38-46: loading card; buttons exist only in the error card and next to a URI
- routes/transaction-model.ts:744-756: the KYC continuation (strings reused by the patch)
wallet-core: pay-peer-pull-credit.ts:136-149 (no URI before ready), 1307-1310 (451 -> merge KYC), 1831-1843 (pending / kyc-required).

Patch (attached, web-peer-share-kyc.patch, applies to origin/master): PeerShareRoute detects a pending transaction with a safe kycUrl and no URI and passes it to PeerShareScreen, which then shows a warning card "Identity verification required" / "Complete the required identity verification on the exchange's website." with "Complete verification" (platform.openExternal(kycUrl)) and "View transaction" (AML-review variants: "Waiting for review" / "View verification details"); while wallet-core is still in kyc-init the status line says "Loading identity verification requirements" instead of "Waiting for a response from the exchange…". All strings already exist in the catalogue. The link appears by itself once the transaction reaches ready.

Verification: built the Chrome extension; after-web-1.png / after-web-2.png show the card for a fresh KUDOS:3 request; "Complete verification" opened https://tripwire.taler.net:8445/kyc-spa/… in a new tab. pnpm typecheck: same 29 pre-existing errors (all in test/*.test.tsx) with and without the patch, none in the touched files; prettier clean.

Assisted by LLM
Steps To Reproduce1. Fund the web wallet with KUDOS:3 from the KYC test exchange https://tripwire.taler.net:8445/ (bank :8446).
2. Balances -> select that KUDOS balance -> Request -> amount 3, description -> Review -> Create link.
3. The share screen stays on "Waiting for a response from the exchange…"; open the transaction from the history: it says "Identity verification required".
TagsNo tags attached.
Attached Files
before-web-1.png (88,931 bytes)   
before-web-1.png (88,931 bytes)   
before-web-2.png (89,761 bytes)   
before-web-2.png (89,761 bytes)   
before-web-3.png (55,040 bytes)   
before-web-3.png (55,040 bytes)   
before-web-4-after-30s.png (55,040 bytes)   
before-web-4-after-30s.png (55,040 bytes)   
before-web-5-detail.png (128,087 bytes)   
before-web-5-detail.png (128,087 bytes)   
before-android-1.png (75,542 bytes)   
before-android-1.png (75,542 bytes)   
before-android-2.png (97,404 bytes)   
before-android-2.png (97,404 bytes)   
before-ios-1.png (121,128 bytes)   
before-ios-1.png (121,128 bytes)   
after-web-1.png (79,169 bytes)   
after-web-1.png (79,169 bytes)   
after-web-2.png (79,169 bytes)   
after-web-2.png (79,169 bytes)   
web-peer-share-kyc.patch (5,262 bytes)   
diff --git a/packages/wallet-webui/src/routes/App.tsx b/packages/wallet-webui/src/routes/App.tsx
index e649abaf4..7772198ab 100644
--- a/packages/wallet-webui/src/routes/App.tsx
+++ b/packages/wallet-webui/src/routes/App.tsx
@@ -2072,7 +2072,7 @@ function PeerCreateRoute(props: { mode: "send" | "request" }) {
 }
 
 function PeerShareRoute() {
-  const { connection } = useServices();
+  const { connection, platform } = useServices();
   const callMutation = useWalletMutation(connection);
   const [, params] = useRoute("/peer/share/:transactionId/:mode");
   const [, navigate] = useLocation();
@@ -2132,7 +2132,20 @@ function PeerShareRoute() {
               /* Translators: Peer payments transfer digital cash between people using links. A shared link can offer money to receive or request money to be paid. */ i18n.str`This peer link is no longer available.`,
             )
           : transactionProblem;
-  const loading = query.isLoading || (!uri && !error);
+  // The exchange may require identity verification before the link exists
+  // (e.g. a request above its limit): say so instead of waiting for it.
+  const kycUrl =
+    transaction &&
+    !uri &&
+    transaction.txState.major === TransactionMajorState.Pending &&
+    safeWebUrl(transaction.kycUrl)
+      ? transaction.kycUrl
+      : undefined;
+  const kycInit =
+    transaction &&
+    !uri &&
+    transaction.txState.minor === TransactionMinorState.KycInit;
+  const loading = query.isLoading || (!uri && !error && !kycUrl);
   const [delayed, setDelayed] = useState(false);
   useEffect(() => {
     setDelayed(false);
@@ -2175,7 +2188,16 @@ function PeerShareRoute() {
       uri={uri}
       loading={loading}
       delayed={delayed}
+      kycInit={Boolean(kycInit)}
       error={error}
+      kyc={
+        kycUrl && !error
+          ? {
+              reviewing: Boolean(transaction?.kycAmlReview),
+              onOpen: () => void platform.openExternal(kycUrl),
+            }
+          : undefined
+      }
       retryable={retryable}
       retrying={retrying}
       onCopy={() => {
diff --git a/packages/wallet-webui/src/screens/PeerShareScreen.tsx b/packages/wallet-webui/src/screens/PeerShareScreen.tsx
index 1b4d2f613..7c5bf7276 100644
--- a/packages/wallet-webui/src/screens/PeerShareScreen.tsx
+++ b/packages/wallet-webui/src/screens/PeerShareScreen.tsx
@@ -10,6 +10,10 @@ export function PeerShareScreen(props: {
   uri?: string;
   loading: boolean;
   delayed?: boolean;
+  /** wallet-core is fetching the exchange's identity verification requirements */
+  kycInit?: boolean;
+  /** the exchange requires identity verification before the link is created */
+  kyc?: { reviewing: boolean; onOpen: () => void };
   error?: ErrorPresentation;
   retryable?: boolean;
   retrying?: boolean;
@@ -38,12 +42,39 @@ export function PeerShareScreen(props: {
       {props.loading && (
         <Card>
           <p role="status">
-            {props.delayed
-              ? /* Translators: An exchange is a GNU Taler service issuing and redeeming digital cash, not an action that converts one currency into another. */ i18n.str`Waiting for a response from the exchange…`
-              : /* Translators: The exchange is preparing a link for a peer transfer or request that the user can share with the other person. */ i18n.str`Preparing a secure share link…`}
+            {props.kycInit
+              ? i18n.str`Loading identity verification requirements`
+              : props.delayed
+                ? /* Translators: An exchange is a GNU Taler service issuing and redeeming digital cash, not an action that converts one currency into another. */ i18n.str`Waiting for a response from the exchange…`
+                : /* Translators: The exchange is preparing a link for a peer transfer or request that the user can share with the other person. */ i18n.str`Preparing a secure share link…`}
           </p>
         </Card>
       )}
+      {props.kyc && (
+        <Card class="border-warning bg-warningContainer">
+          <h2 role="alert" class="font-semibold text-onWarningContainer">
+            {props.kyc.reviewing
+              ? i18n.str`Waiting for review`
+              : i18n.str`Identity verification required`}
+          </h2>
+          <p class="mt-2 text-sm text-onWarningContainer">
+            {props.kyc.reviewing
+              ? i18n.str`The exchange is reviewing your account. Please wait.`
+              : /* Translators: An exchange is a GNU Taler service issuing and redeeming digital cash, not an action that converts one currency into another. */ i18n.str`Complete the required identity verification on the exchange's website.`}
+          </p>
+          <div class="mt-4 flex flex-wrap justify-end gap-3">
+            <Button
+              tone="secondary"
+              onClick={props.onDone}
+            >{i18n.str`View transaction`}</Button>
+            <Button onClick={props.kyc.onOpen}>
+              {props.kyc.reviewing
+                ? i18n.str`View verification details`
+                : i18n.str`Complete verification`}
+            </Button>
+          </div>
+        </Card>
+      )}
       {props.error && (
         <ErrorCard error={props.error}>
           {props.retryable && (
web-peer-share-kyc.patch (5,262 bytes)   

Required notifications

Address or linkRemarkAdded byNotifiedActions

Relationships

related to 0011956 planning Request payment (invoice): the flow dies with "Unknown error" whenever wallet-core omits the deprecated `talerUri` from `initiatePeerPullCredit` 

Activities

Issue History

Date ModifiedUsernameFieldChange
2026-11-11 01:28bot-cgNew Issue
2026-11-11 01:28bot-cgRelationship addedrelated to 0011956
2026-11-11 01:28bot-cgFile Added: before-web-1.png
2026-11-11 01:28bot-cgFile Added: before-web-2.png
2026-11-11 01:28bot-cgFile Added: before-web-3.png
2026-11-11 01:28bot-cgFile Added: before-web-4-after-30s.png
2026-11-11 01:28bot-cgFile Added: before-web-5-detail.png
2026-11-11 01:28bot-cgFile Added: before-android-1.png
2026-11-11 01:28bot-cgFile Added: before-android-2.png
2026-11-11 01:28bot-cgFile Added: before-ios-1.png
2026-11-11 01:28bot-cgFile Added: after-web-1.png
2026-11-11 01:28bot-cgFile Added: after-web-2.png
2026-11-11 01:28bot-cgFile Added: web-peer-share-kyc.patch