Skip to content

Conversation

@ganchoradkov
Copy link
Member

Summary

  • Enhanced isPaymentLink function to detect payment links embedded in WalletConnect URIs
  • Handles both URL-encoded and non-encoded pay= query parameters in WC URIs
  • Bumped @walletconnect/react-native-compat to 2.23.2-canary.4

Supported payment link formats:

  1. Direct payment URL:

    https://pay.walletconnect.com/?pid=pay_95a2ecc101KEYG1NH580DF2J04MBNRWE7V
    
  2. WC URI with pay parameter (non-encoded):

    wc:...&pay=https://pay.walletconnect.com/?pid=pay_...
    
  3. WC URI with pay parameter (URL-encoded):

    wc:...&pay=https%3A%2F%2Fpay.walletconnect.com%2F%3Fpid%3Dpay_...
    

Test plan

  • Test with direct payment URL
  • Test with WC URI containing non-encoded pay parameter
  • Test with WC URI containing URL-encoded pay parameter
  • Verify existing payment flow still works

- Update isPaymentLink to detect payment links embedded in WC URIs
- Handle both URL-encoded and non-encoded pay= parameters
- Bump @walletconnect/react-native-compat to 2.23.2-canary.4
Copilot AI review requested due to automatic review settings January 15, 2026 10:53
@vercel
Copy link

vercel bot commented Jan 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
react-native-examples Ready Ready Preview, Comment Jan 15, 2026 6:53pm

Review with Vercel Agent

@claude
Copy link

claude bot commented Jan 15, 2026

Claude finished @ganchoradkov's task in 1m 5s —— View job


Code Review Complete

Analyzed changes to payment link detection logic.

Tasks

  • Read changed files
  • Analyze implementation for issues
  • Run automated checks
  • Post review findings

Found 1 issue(s)

Issue 1: Redundant URL decoding may cause incorrect behavior

ID: walletkitutil-redundant-decode-a3f2
File: wallets/rn_cli_wallet/src/utils/WalletKitUtil.ts:45
Severity: MEDIUM
Category: code_quality
Context: URLSearchParams.get() already automatically decodes URL-encoded parameter values. Calling decodeURIComponent() on the result performs a second decode, which could fail or produce incorrect results if the URL contains characters that look like encoded sequences (e.g., a literal %20 in the URL would be decoded twice).
Recommendation: Remove the redundant decodeURIComponent() call:

// Replace this:
const decodedPayUrl = decodeURIComponent(payParam);
return isPaymentUrl(decodedPayUrl);

// With this:
return isPaymentUrl(payParam);

Automated Checks

✅ No workflow security issues detected
✅ No WalletConnect Pay architecture violations detected
✅ No external domain URLs detected (pay.walletconnect.com is approved)
✅ No static resource cache-control issues detected

const params = new URLSearchParams(queryString);
const payParam = params.get('pay');
if (payParam) {
const decodedPayUrl = decodeURIComponent(payParam);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Review Issue: Redundant URL decoding may cause incorrect behavior

Severity: MEDIUM
Category: code_quality
Tool: Claude Auto Review

Context: URLSearchParams.get() already automatically decodes URL-encoded parameter values. Calling decodeURIComponent() on the result performs a second decode, which could fail or produce incorrect results if the URL contains characters that look like encoded sequences (e.g., a literal %20 in the URL would be decoded twice).

Recommendation: Remove the redundant decodeURIComponent() call:

// Replace this:
const decodedPayUrl = decodeURIComponent(payParam);
return isPaymentUrl(decodedPayUrl);

// With this:
return isPaymentUrl(payParam);

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the isPaymentLink function to detect WalletConnect payment links embedded within WC URIs as query parameters, in addition to detecting direct payment URLs. It also bumps the @walletconnect/react-native-compat package to version 2.23.2-canary.4.

Changes:

  • Enhanced isPaymentLink to parse WC URIs and check for pay= query parameters
  • Extracted payment URL validation logic into a separate isPaymentUrl helper function
  • Updated @walletconnect/react-native-compat from 2.23.2-canary.1 to 2.23.2-canary.4

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.

File Description
wallets/rn_cli_wallet/src/utils/WalletKitUtil.ts Added logic to detect and validate payment links in WC URIs; refactored validation into helper function
wallets/rn_cli_wallet/package.json Bumped @walletconnect/react-native-compat to 2.23.2-canary.4
wallets/rn_cli_wallet/yarn.lock Updated lockfile checksums for dependency version change
Comments suppressed due to low confidence (1)

wallets/rn_cli_wallet/src/utils/WalletKitUtil.ts:66

  • The enhanced isPaymentLink function introduces new logic for parsing WC URIs with pay parameters, but there are no tests covering this new behavior. Since the codebase has a jest configuration and a test directory, consider adding unit tests to verify:
  • Direct payment URLs are correctly identified
  • WC URIs with URL-encoded pay parameters are correctly handled
  • WC URIs with non-encoded pay parameters are correctly handled
  • Invalid WC URIs return false
  • Edge cases like missing query strings or invalid URLs are handled properly
export function isPaymentLink(uri: string): boolean {
  // Handle WC URI with pay= parameter (e.g., wc:...&pay=https://pay.walletconnect.com/...)
  if (uri.startsWith('wc:')) {
    const queryStart = uri.indexOf('?');
    if (queryStart === -1) {
      return false;
    }
    const queryString = uri.substring(queryStart + 1);
    const params = new URLSearchParams(queryString);
    const payParam = params.get('pay');
    if (payParam) {
      const decodedPayUrl = decodeURIComponent(payParam);
      return isPaymentUrl(decodedPayUrl);
    }
    return false;
  }

  // Handle direct payment URL
  return isPaymentUrl(uri);
}

function isPaymentUrl(url: string): boolean {
  try {
    const parsed = new URL(url);
    const hostname = parsed.hostname.toLowerCase();
    const isPayHost =
      hostname === 'pay.walletconnect.com' ||
      hostname === 'www.pay.walletconnect.com';
    return isPayHost && parsed.searchParams.has('pid');
  } catch {
    return false;
  }
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +45 to +46
const decodedPayUrl = decodeURIComponent(payParam);
return isPaymentUrl(decodedPayUrl);
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URLSearchParams.get method already returns a decoded value, so calling decodeURIComponent on it will result in double-decoding. This could cause issues if the payment URL contains percent-encoded characters that should remain encoded, or if it contains characters like % that aren't part of a valid percent-encoding sequence.

Remove the decodeURIComponent call and use the payParam value directly, as URLSearchParams already handles the decoding.

Suggested change
const decodedPayUrl = decodeURIComponent(payParam);
return isPaymentUrl(decodedPayUrl);
return isPaymentUrl(payParam);

Copilot uses AI. Check for mistakes.
// Handle direct payment URL
return isPaymentUrl(uri);
}

Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly introduced isPaymentUrl helper function lacks documentation. Since it's an internal helper function used by isPaymentLink, consider adding a JSDoc comment explaining its purpose, parameters, and return value to improve code maintainability.

Suggested change
/**
* Internal helper that determines whether a given URL string
* represents a valid WalletConnect Pay payment URL.
*
* A valid payment URL must:
* - Use the `pay.walletconnect.com` (or `www.pay.walletconnect.com`) host, and
* - Include a `pid` query parameter.
*
* Invalid or non-parseable URLs will return `false`.
*
* @param url - The URL string to validate as a WalletConnect Pay payment link.
* @returns `true` if the URL is a WalletConnect Pay payment URL, otherwise `false`.
*/

Copilot uses AI. Check for mistakes.
Comment on lines 33 to +54
// Check if a URI is a WalletConnect Pay payment link
export function isPaymentLink(uri: string): boolean {
// Handle WC URI with pay= parameter (e.g., wc:...&pay=https://pay.walletconnect.com/...)
if (uri.startsWith('wc:')) {
const queryStart = uri.indexOf('?');
if (queryStart === -1) {
return false;
}
const queryString = uri.substring(queryStart + 1);
const params = new URLSearchParams(queryString);
const payParam = params.get('pay');
if (payParam) {
const decodedPayUrl = decodeURIComponent(payParam);
return isPaymentUrl(decodedPayUrl);
}
return false;
}

// Handle direct payment URL
return isPaymentUrl(uri);
}

Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a WC URI with an embedded payment link is detected, the full WC URI is passed to handlePaymentLink, but this function expects to receive only the payment URL. The Pay SDK's getPaymentOptions method will likely fail when given a WC URI instead of the actual payment URL.

Consider adding a helper function to extract the payment URL from a WC URI, and ensure that handlePaymentLink always receives the actual payment URL regardless of whether the input was a direct payment URL or a WC URI with a pay parameter.

Suggested change
// Check if a URI is a WalletConnect Pay payment link
export function isPaymentLink(uri: string): boolean {
// Handle WC URI with pay= parameter (e.g., wc:...&pay=https://pay.walletconnect.com/...)
if (uri.startsWith('wc:')) {
const queryStart = uri.indexOf('?');
if (queryStart === -1) {
return false;
}
const queryString = uri.substring(queryStart + 1);
const params = new URLSearchParams(queryString);
const payParam = params.get('pay');
if (payParam) {
const decodedPayUrl = decodeURIComponent(payParam);
return isPaymentUrl(decodedPayUrl);
}
return false;
}
// Handle direct payment URL
return isPaymentUrl(uri);
}
// Extract a WalletConnect Pay payment URL from a given URI (WC URI or direct payment URL)
export function extractPaymentUrl(uri: string): string | null {
if (!uri) {
return null;
}
// Handle WC URI with pay= parameter (e.g., wc:...&pay=https://pay.walletconnect.com/...)
if (uri.startsWith('wc:')) {
const queryStart = uri.indexOf('?');
if (queryStart === -1) {
return null;
}
const queryString = uri.substring(queryStart + 1);
const params = new URLSearchParams(queryString);
const payParam = params.get('pay');
if (!payParam) {
return null;
}
const decodedPayUrl = decodeURIComponent(payParam);
return isPaymentUrl(decodedPayUrl) ? decodedPayUrl : null;
}
// Handle direct payment URL
return isPaymentUrl(uri) ? uri : null;
}
// Check if a URI is a WalletConnect Pay payment link
export function isPaymentLink(uri: string): boolean {
return extractPaymentUrl(uri) !== null;
}

Copilot uses AI. Check for mistakes.
}
}

// Check if a URI is a WalletConnect Pay payment link
Copy link

Copilot AI Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment describes the function as checking if a URI is a WalletConnect Pay payment link, but it doesn't mention that the function also validates the hostname and pid parameter. Consider updating the comment to be more descriptive: "Check if a URI is a valid WalletConnect Pay payment link (either a direct payment URL or a WC URI with a pay parameter)"

Suggested change
// Check if a URI is a WalletConnect Pay payment link
// Check if a URI is a valid WalletConnect Pay payment link (either a direct payment URL or a WC URI with a pay parameter)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants