Skip to content

[bug]: [Android] MetaMask opens via Deep Link but transaction popup (approve) does not appear despite 'verified' domain and SIWX #520

@DreamBoysYJ

Description

@DreamBoysYJ

Description

Description

I am experiencing an issue where MetaMask opens but fails to show the transaction confirmation (approve) popup.
Even though my domain is fully verified and SIWX is configured, the transaction request seems to be ignored by MetaMask after the redirect.

Environment

  • SDK: @reown/appkit-ethers-react-native
  • Platform: Android (Physical Device)
  • Wallet: MetaMask (Latest version)
  • Domain Status: Confirmed as paykingos.com: verified via adb shell pm get-app-links

Steps to Reproduce

  1. Configure AppKit with ReownAuthentication and linkMode: false (to use standard deep links).
  2. Connect wallet and complete SIWX (Sign-In With Ethereum) successfully.
  3. Call contract.approve() using ethers BrowserProvider.
  4. The app redirects to MetaMask, but no transaction popup appears.

What I've Already Tried

  • Set linkMode: false to avoid Universal Link parsing issues in MetaMask.
  • Added staticNetwork: true to BrowserProvider and explicitly injected chainId: 137.
  • Removed all custom gas options to let MetaMask handle estimation.
  • Verified that the AppKit configuration is initialized outside the component tree (api/appkit.ts).
  • Cleared MetaMask activity and cache.

Code Snippets

AppKit Config:

export const appKit = createAppKit({
  projectId: 'YOUR_PROJECT_ID',
  metadata: {
    name: 'PayKing OS',
    url: '[https://paykingos.com](https://paykingos.com)',
    redirect: {
      native: 'paykingos://',
      universal: '[https://paykingos.com](https://paykingos.com)',
      linkMode: false,
    },
  },
  siwx: new ReownAuthentication(),
  networks: [POLYGON_MAINNET],
  defaultNetwork: POLYGON_MAINNET,
});

Additional Context
The SIWX "Sign In" prompt works perfectly and returns to the app. The issue only happens during the eth_sendTransaction (approve) call. It seems like the deep link payload is not being correctly interpreted by MetaMask on Android.

AppKit SDK version

"@reown/appkit-common": "^1.8.15",     "@reown/appkit-ethers-react-native": "^2.0.1",     "@reown/appkit-react-native": "^2.0.1",

Output of npx react-native info

System:
OS: macOS 15.5
CPU: (8) arm64 Apple M1 Pro
Memory: 204.23 MB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 23.10.0
path: /Users/youngju/.nvm/versions/node/v23.10.0/bin/node
Yarn:
version: 1.22.19
path: /opt/homebrew/bin/yarn
npm:
version: 10.9.2
path: /Users/youngju/.nvm/versions/node/v23.10.0/bin/npm
Watchman: Not Found
Managers:
CocoaPods: Not Found
SDKs:
iOS SDK: Not Found
Android SDK: Not Found
IDEs:
Android Studio: 2025.2 AI-252.27397.103.2522.14514259
Xcode:
version: /undefined
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.17
path: /opt/homebrew/Cellar/openjdk@17/17.0.17/libexec/openjdk.jdk/Contents/Home/bin/javac
Ruby:
version: 3.4.2
path: /opt/homebrew/opt/ruby/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 20.0.0
wanted: 20.0.0
react:
installed: 19.2.0
wanted: 19.2.0
react-native:
installed: 0.83.1
wanted: 0.83.1
react-native-macos: Not Found
npmGlobalPackages:
"react-native": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: Not found
newArchEnabled: false

Expo Version (if applies)

No response

Steps to reproduce

Environment Setup: Ensure the Android app is configured with @reown/appkit-ethers-react-native and the domain paykingos.com is verified with verified status via adb shell pm get-app-links.

Initialization: Initialize AppKit outside the component tree with ReownAuthentication for SIWX and linkMode: false to use standard deep links.

Wallet Connection: Launch the app, open the AppKit modal, and select MetaMask.

Authentication: Complete the SIWX (Sign-In With Ethereum) process. The app should redirect to MetaMask for signing and return to the dapp successfully.

Network Check: Ensure the wallet is on Polygon Mainnet (Chain ID: 137).

Trigger Transaction: Call the approve function of an ERC20 contract using ethers.js BrowserProvider.

The Bug: The app redirects to the MetaMask app, but no transaction confirmation popup appears. MetaMask just stays on the wallet home screen.

Snack, code example, screenshot, or link to a repository

import { useState } from 'react';
import { Alert } from 'react-native';
import { BrowserProvider, Contract, parseUnits } from 'ethers';
import { useAccount, useProvider } from '@reown/appkit-react-native';
import { ERC20_ABI } from '../constants/abis';
import { CONFIG, TOKENS, GAS_OPTIONS } from '../constants/index';

export const useApprove = () => {
  const [loading, setLoading] = useState(false);
  const { provider } = useProvider(); // AppKit에서 제공하는 지갑 공급자
  const { isConnected, address } = useAccount();

  const requestApprove = async (
    tokenSymbol: 'USDT' | 'USDC',
    amount: string,
  ) => {
    if (!isConnected || !provider) return;

    setLoading(true);
    try {
      // 🚀 [추가] 지갑에 폴리곤(0x89)으로 네트워크 전환 명령을 내립니다.
      // 메타마스크가 이더리움에 있어도 이 코드를 만나면 폴리곤 전환 창을 띄웁니다.
      await (provider as any).request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: '0x89' }], // 137의 16진수
      });

      const ethersProvider = new BrowserProvider(
        provider,
        {
          chainId: 137,
          name: 'polygon',
        },
        { staticNetwork: true },
      ); // 👈 [핵심] 정적 네트워크 옵션으로 오버헤드 제거
      const signer = await ethersProvider.getSigner();
      const tokenAddress = TOKENS[tokenSymbol];
      const contract = new Contract(tokenAddress, ERC20_ABI, signer);

      const parsedAmount = parseUnits(amount, 6);

      // [방어 4] 가스 추정 에러 및 정체 방지
      // gasLimit을 수동으로 주어 'estimateGas' 에러를 우회하고,
      // 사장님의 GAS_OPTIONS(60/120 gwei 등)를 적용해 광속 처리를 유도합니다.
      const tx = await contract.approve(CONFIG.SPENDER_ADDR, parsedAmount, {
        ...GAS_OPTIONS,
        gasLimit: 150000,
        chainId: 137, // 👈 [추가] 메타마스크가 딴맘 못 먹게 쐐기를 박습니다.
      });

      console.log(`[${tokenSymbol}] 승인 트랜잭션 제출됨:`, tx.hash);

      // [방어 5] 블록 확정 대기
      // 사용자가 앱으로 돌아왔을 때 실제 결과가 나올 때까지 기다립니다.
      const receipt = await tx.wait(1);

      if (receipt.status === 1) {
        return { success: true, hash: tx.hash };
      } else {
        throw new Error('트랜잭션이 블록체인에서 거절되었습니다.');
      }
    } catch (error: any) {
      console.error('Approve 에러:', error);

      // 사용자 취소 시 에러 메시지 순화
      const errorMessage =
        error.code === 'ACTION_REJECTED'
          ? '사용자가 지갑에서 승인을 거절했습니다.'
          : error.reason || error.message || '네트워크 오류가 발생했습니다.';

      Alert.alert('승인 실패', errorMessage);
    } finally {
      setLoading(false);
    }
  };

  return { requestApprove, loading };
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingquestionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions