Skip to content

Commit

Permalink
feat: support TMA
Browse files Browse the repository at this point in the history
  • Loading branch information
wenty22 committed Aug 27, 2024
1 parent e39f405 commit 29661f4
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 27 deletions.
1 change: 1 addition & 0 deletions examples/nextjs/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const config: WalletKitConfig = {
evmConfig({
autoConnect: true,
initialChainId: 1,
walletConnectProjectId: 'e68a1816d39726c2afabf05661a32767',
wallets: [metaMask(), trustWallet(), walletConnect()],
chains: [mainnet] as any[],
}),
Expand Down
1 change: 1 addition & 0 deletions examples/vite/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const config: WalletKitConfig = {
evmConfig({
autoConnect: true,
initialChainId: 1,
walletConnectProjectId: 'e68a1816d39726c2afabf05661a32767',
wallets: [metaMask(), trustWallet(), walletConnect()],
chains: [mainnet] as any[],
}),
Expand Down
4 changes: 1 addition & 3 deletions packages/walletkit/__dev__/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ const config: WalletKitConfig = {
walletConnectProjectId: 'e68a1816d39726c2afabf05661a32767',
chains: [mainnet, bsc],
wallets: [
metaMask({
useWalletConnect: true,
}),
metaMask(),
trustWallet(),
walletConnect(),
binanceWeb3Wallet(),
Expand Down
14 changes: 14 additions & 0 deletions packages/walletkit/src/core/base/utils/mobile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,17 @@ export function isIOS(): boolean {
export function isMobile(): boolean {
return isAndroid() || isIOS();
}

// telegram mini app
export function isTMA(): boolean {
const check = (host: any) => {
return (
typeof host !== 'undefined' &&
'TelegramWebviewProxy' in host &&
'postEvent' in host.TelegramWebviewProxy &&
typeof host.TelegramWebviewProxy.postEvent === 'function'
);
};

return check(window);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export function ConnectingView(props: ConnectingViewProps) {
const downloadUrl = useWalletDownloadUrl(wallet.downloadUrls);

useEffect(() => {
log('[connecting page]', `name: ${wallet?.name}, status: ${status}`);

if (status === CONNECT_STATUS.UNAVAILABLE || !isReady) return;

const connectTimeout = setTimeout(runConnect, 600);
Expand All @@ -43,8 +45,6 @@ export function ConnectingView(props: ConnectingViewProps) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isReady]);

log('[connecting page]', `name: ${wallet?.name}, status: ${status}`);

const isError = [
CONNECT_STATUS.FAILED,
CONNECT_STATUS.NOTCONNECTED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState, useRef, useMemo, useCallback } from 'react';
import { RouteContext } from './context';
import { EvmConnectingView } from '@/evm/components/EvmConnectingView';
import { EvmConnectWithQRCodeView } from '@/evm/components/EvmConnectWithQRCodeView';
import { EvmConnectWithWalletConnect } from '@/evm/components/EvmConnectWithWalletConnect';
import { EvmConnectWithWalletConnectView } from '@/evm/components/EvmConnectWithWalletConnectView';
import { SolanaConnectingView } from '@/solana/components/SolanaConnectingView';
import { SolanaConnectWithQRCodeView } from '@/solana/components/SolanaConnectWithQRCodeView';
import { ConnectorsView } from '../ConnectorsView';
Expand All @@ -11,7 +11,7 @@ export enum ViewRoutes {
CONNECTORS = 'Connectors',
EVM_CONNECTING = 'EvmConnecting',
EVM_CONNECT_WITH_QRCODE = 'EvmConnectWithQRCode',
EVM_CONNECT_WITH_WALLET_CONNECT = 'EvmConnectWithWalletConnect',
EVM_CONNECT_WITH_WALLET_CONNECT = 'EvmConnectWithWalletConnectView',
SOLANA_CONNECTING = 'SolanaConnecting',
SOLANA_CONNECT_WITH_QRCODE = 'SolanaConnectWithQRCode',
}
Expand All @@ -35,7 +35,7 @@ export function RouteProvider(props: RouteProviderProps) {
case ViewRoutes.EVM_CONNECT_WITH_QRCODE:
return <EvmConnectWithQRCodeView />;
case ViewRoutes.EVM_CONNECT_WITH_WALLET_CONNECT:
return <EvmConnectWithWalletConnect />;
return <EvmConnectWithWalletConnectView />;
case ViewRoutes.SOLANA_CONNECTING:
return <SolanaConnectingView />;
case ViewRoutes.SOLANA_CONNECT_WITH_QRCODE:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ThemeProvider } from '../ThemeProvider';
import { useMemo, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { EvmWalletProvider } from '@/evm/components/EvmWalletProvider';
import { SolanaWalletProvider } from '@/solana/components/SolanaWalletProvider';
import { Action, WalletKitConfig, WalletKitContext } from './context';
Expand All @@ -8,6 +8,7 @@ import { ConnectModalProvider } from '@/core/modals/ConnectModal/provider';
import { ToastProvider } from '@/core/base/components/toast/ToastProvider';
import { BaseWallet } from '@/core/configs/types';
import { ProfileModalProvider } from '@/core/modals/ProfileModal/provider';
import { isTMA } from '@/core/base/utils/mobile';

export interface WalletKitProviderProps {
config: WalletKitConfig;
Expand Down Expand Up @@ -56,6 +57,17 @@ export function WalletKitProvider(props: WalletKitProviderProps) {
};
}, [action, config.debug, finalConfig, selectedWallet, wallets]);

// TMA hack
useEffect(() => {
if (isTMA()) {
window.open = (function (open) {
return function (url, _, features) {
return open.call(window, url, '_blank', features);
};
})(window.open);
}
}, []);

return (
<WalletKitContext.Provider value={value}>
<ToastProvider />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ConnectWithQRCode } from '@/core/modals/ConnectModal/ConnectWithQRCode';
import { useSelectedWallet } from '@/core/providers/WalletKitProvider/context';
import { useEvmIsConnected } from '@/evm/hooks/useEvmIsConnected';
import { useQRCodeUri } from '@/evm/hooks/useQRCodeUri';
import { useWalletConnectUri } from '@/evm/hooks/useWalletConnectUri';
import { useWalletConnectModal } from '@/evm/hooks/useWalletConnectModal';
import { EvmWallet, isWalletConnect } from '@/evm/wallets';

export function EvmConnectWithQRCodeView() {
const { selectedWallet } = useSelectedWallet();

const wcUri = useQRCodeUri();
const wcUri = useWalletConnectUri();
const wcModal = useWalletConnectModal();
const qrCodeUri = wcUri && ((selectedWallet as EvmWallet).getUri?.(wcUri) ?? wcUri);
const isConnected = useEvmIsConnected();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { CONNECT_STATUS } from '@/core/constants';
import { ConnectingView } from '@/core/modals/ConnectModal/ConnectingView';
import { useSelectedWallet } from '@/core/providers/WalletKitProvider/context';
import { useLogger, useSelectedWallet } from '@/core/providers/WalletKitProvider/context';
import { useEvmIsConnected } from '@/evm/hooks/useEvmIsConnected';
import { useQRCodeUri } from '@/evm/hooks/useQRCodeUri';
import { useWalletConnectUri } from '@/evm/hooks/useWalletConnectUri';
import { EvmWallet } from '@/evm/wallets';
import { useCallback, useState } from 'react';

export function EvmConnectWithWalletConnect() {
export function EvmConnectWithWalletConnectView() {
const { selectedWallet } = useSelectedWallet();

const log = useLogger();
const [status, setStatus] = useState(CONNECT_STATUS.CONNECTING);

const wcUri = useQRCodeUri({
const wcUri = useWalletConnectUri({
onError(error: any) {
if (error.code) {
// https://github.com/MetaMask/eth-rpc-errors/blob/main/src/error-constants.ts
Expand Down Expand Up @@ -42,13 +43,15 @@ export function EvmConnectWithWalletConnect() {
},
});

const qrCodeUri = (selectedWallet as EvmWallet).getUri(wcUri);
const walletUri = (selectedWallet as EvmWallet).getUri(wcUri);
const isConnected = useEvmIsConnected();

const onClickConnect = useCallback(() => {
log(`[connectWithWalletConnect] walletUri`, walletUri);
setStatus(CONNECT_STATUS.CONNECTING);
window.open(qrCodeUri, '_self', 'noopener noreferrer');
}, [qrCodeUri]);
window.open(walletUri, '_self', 'noopener noreferrer');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletUri]);

return (
<ConnectingView
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UseWalletRenderProps } from '@/core/hooks/useWalletRender';
import { isMobile } from '@/core/index';
import { isMobile, isTMA } from '@/core/index';
import { useConnectModal } from '@/core/modals/ConnectModal/context';
import { ViewRoutes } from '@/core/modals/ConnectModal/RouteProvider';
import { useRouter } from '@/core/modals/ConnectModal/RouteProvider/context';
Expand Down Expand Up @@ -33,7 +33,6 @@ export function SetEvmWalletClickRef(props: SetEvmWalletClickRefProps) {
const router = useRouter();

const timerRef = useRef<any>();
const mobile = isMobile();
const { wallets } = useEvmConfig();

clickRef.current = (walletId: string, e: React.MouseEvent<Element, MouseEvent>) => {
Expand Down Expand Up @@ -75,8 +74,15 @@ export function SetEvmWalletClickRef(props: SetEvmWalletClickRefProps) {

clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
if (mobile) {
// 1. mobile
if (isTMA()) {
// 1. TMA
if (isMobile()) {
jumpToWalletConnectView();
} else {
jumpToQRCodeView();
}
} else if (isMobile()) {
// 2. mobile
if (isWalletConnect(walletId)) {
wcModal.onOpen();
} else if (wallet.useWalletConnect) {
Expand All @@ -92,7 +98,7 @@ export function SetEvmWalletClickRef(props: SetEvmWalletClickRefProps) {
}
}
} else {
// 2. pc
// 3. pc
if (isWalletConnect(walletId)) {
if (wallet.showQRCode) {
jumpToQRCodeView();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { ConnectErrorType } from 'wagmi/actions';

let timer: any;

interface UseQRCodeUriProps {
interface UseWalletConnectUriProps {
onError?: (error: ConnectErrorType) => void;
}

export function useQRCodeUri(props?: UseQRCodeUriProps) {
export function useWalletConnectUri(props?: UseWalletConnectUriProps) {
const { connectAsync } = useConnect();

const eventConfig = useEventConfig();
Expand Down
9 changes: 8 additions & 1 deletion packages/walletkit/src/evm/wallets/metaMask/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { metaMaskConfig } from '@/core/configs/metaMask';
import { hasEvmInjectedProvider } from '../utils';
import { injected } from '../injected';
import { InjectedEvmWalletOptions, EvmWallet } from '../types';
import { isMobile, isTMA } from '@/core/index';

export function metaMask(props: InjectedEvmWalletOptions = {}): EvmWallet {
const { connectorOptions, ...restProps } = props;
Expand All @@ -20,7 +21,13 @@ export function metaMask(props: InjectedEvmWalletOptions = {}): EvmWallet {
return `dapp://${dappPath}`;
},
getUri(uri) {
return `metamask://wc?uri=${encodeURIComponent(uri)}`;
const wcUri = `wc?uri=${encodeURIComponent(uri)}`;

if (isTMA() && isMobile()) {
return `https://metamask.app.link/${wcUri}`;
}

return `metamask://${wcUri}`;
},
getCreateConnectorFn() {
return injected({
Expand Down
9 changes: 8 additions & 1 deletion packages/walletkit/src/evm/wallets/trustWallet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { trustWalletConfig } from '@/core/configs/trustWallet';
import { injected } from '../injected';
import { EvmWallet, InjectedEvmWalletOptions } from '../types';
import { getEvmInjectedProvider } from '../utils';
import { isMobile, isTMA } from '@/core/index';

export function trustWallet(props: InjectedEvmWalletOptions = {}): EvmWallet {
const { connectorOptions, ...restProps } = props;
Expand All @@ -23,7 +24,13 @@ export function trustWallet(props: InjectedEvmWalletOptions = {}): EvmWallet {
return dappPath;
},
getUri(uri) {
return `trust://wc?uri=${encodeURIComponent(uri)}`;
const wcUri = `wc?uri=${encodeURIComponent(uri)}`;

if (isTMA() && isMobile()) {
return `https://link.trustwallet.com/${wcUri}`;
}

return `trust://${wcUri}`;
},
getCreateConnectorFn() {
return injected({
Expand Down

0 comments on commit 29661f4

Please sign in to comment.