Skip to content

Commit

Permalink
feat: Add ConnectWithWalletConnect view
Browse files Browse the repository at this point in the history
  • Loading branch information
wenty22 committed Aug 26, 2024
1 parent f039f21 commit e39f405
Show file tree
Hide file tree
Showing 29 changed files with 420 additions and 158 deletions.
6 changes: 4 additions & 2 deletions packages/walletkit/__dev__/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
binanceWeb3Wallet,
bitgetWallet,
coinbaseWallet,
EthereumScript,
evmConfig,
mathWallet,
metaMask,
Expand Down Expand Up @@ -50,9 +49,12 @@ const config: WalletKitConfig = {
evmConfig({
autoConnect: true,
initialChainId: 1,
walletConnectProjectId: 'e68a1816d39726c2afabf05661a32767',
chains: [mainnet, bsc],
wallets: [
metaMask(),
metaMask({
useWalletConnect: true,
}),
trustWallet(),
walletConnect(),
binanceWeb3Wallet(),
Expand Down
3 changes: 2 additions & 1 deletion packages/walletkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
"build": "vite build"
},
"peerDependencies": {
"@tanstack/react-query": "^5",
"react": ">=17",
"react-dom": ">=17",
"@tanstack/react-query": "^5",
"viem": "^2",
"wagmi": "^2"
},
Expand Down Expand Up @@ -72,6 +72,7 @@
"viem": "^2.17.4",
"vite": "^4.5.3",
"vite-plugin-dts": "^3.9.1",
"vite-plugin-mkcert": "^1.17.6",
"wagmi": "^2.10.10"
}
}
13 changes: 5 additions & 8 deletions packages/walletkit/src/core/configs/getDefaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import { EvmConfig } from '@/evm/utils/evmConfig';
type DefaultConfig = Pick<WalletKitContextProps, 'appearance' | 'eventConfig' | 'walletConfig'>;

export function getDefaultConfig(config: WalletKitConfig): DefaultConfig {
const evmConfig = config.walletConfigs.find((item) => item.walletType === 'evm') as EvmConfig;
const { appearance, eventConfig, walletConfigs } = config;

const solanaConfig = config.walletConfigs.find(
(item) => item.walletType === 'solana',
) as SolanaConfig;
const evmConfig = walletConfigs.find((item) => item.walletType === 'evm') as EvmConfig;
const solanaConfig = walletConfigs.find((item) => item.walletType === 'solana') as SolanaConfig;

return {
appearance: {
Expand All @@ -27,7 +26,7 @@ export function getDefaultConfig(config: WalletKitConfig): DefaultConfig {

walletDownloadUrl: `https://trustwallet.com/`,

...config.appearance,
...appearance,
},

eventConfig: {
Expand All @@ -43,7 +42,7 @@ export function getDefaultConfig(config: WalletKitConfig): DefaultConfig {
});
}
},
...config.eventConfig,
...eventConfig,
},

walletConfig: {
Expand All @@ -52,5 +51,3 @@ export function getDefaultConfig(config: WalletKitConfig): DefaultConfig {
},
};
}

export const WALLET_CONNECT_PROJECT_ID = 'e68a1816d39726c2afabf05661a32767';
1 change: 1 addition & 0 deletions packages/walletkit/src/core/configs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface BaseWallet extends WalletConfig {
isVisible?: boolean;
render?: (props: WalletRenderProps) => React.ReactNode;
showQRCode?: boolean;
useWalletConnect?: boolean;
isInstalled: () => boolean | undefined;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,25 @@ interface ConnectingViewProps {
runConnect: () => void;
wallet: BaseWallet;
isConnected: boolean;
isReady?: boolean;
}

export function ConnectingView(props: ConnectingViewProps) {
const { status, runConnect, wallet, isConnected } = props;
const { status, runConnect, wallet, isConnected, isReady = true } = props;

const log = useLogger();
const logos = useWalletLogos(wallet.logos);
const downloadUrl = useWalletDownloadUrl(wallet.downloadUrls);

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

const connectTimeout = setTimeout(runConnect, 600);
return () => {
clearTimeout(connectTimeout);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [isReady]);

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +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 { SolanaConnectingView } from '@/solana/components/SolanaConnectingView';
import { SolanaConnectWithQRCodeView } from '@/solana/components/SolanaConnectWithQRCodeView';
import { ConnectorsView } from '../ConnectorsView';
Expand All @@ -10,6 +11,7 @@ export enum ViewRoutes {
CONNECTORS = 'Connectors',
EVM_CONNECTING = 'EvmConnecting',
EVM_CONNECT_WITH_QRCODE = 'EvmConnectWithQRCode',
EVM_CONNECT_WITH_WALLET_CONNECT = 'EvmConnectWithWalletConnect',
SOLANA_CONNECTING = 'SolanaConnecting',
SOLANA_CONNECT_WITH_QRCODE = 'SolanaConnectWithQRCode',
}
Expand All @@ -32,6 +34,8 @@ export function RouteProvider(props: RouteProviderProps) {
return <EvmConnectingView />;
case ViewRoutes.EVM_CONNECT_WITH_QRCODE:
return <EvmConnectWithQRCodeView />;
case ViewRoutes.EVM_CONNECT_WITH_WALLET_CONNECT:
return <EvmConnectWithWalletConnect />;
case ViewRoutes.SOLANA_CONNECTING:
return <SolanaConnectingView />;
case ViewRoutes.SOLANA_CONNECT_WITH_QRCODE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export function EvmConnectWithQRCodeView() {

const wcUri = useQRCodeUri();
const wcModal = useWalletConnectModal();
const qrCodeUri = wcUri && ((selectedWallet as EvmWallet).getQRCodeUri?.(wcUri) ?? wcUri);
const qrCodeUri = wcUri && ((selectedWallet as EvmWallet).getUri?.(wcUri) ?? wcUri);
const isConnected = useEvmIsConnected();

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { CONNECT_STATUS } from '@/core/constants';
import { ConnectingView } from '@/core/modals/ConnectModal/ConnectingView';
import { useSelectedWallet } from '@/core/providers/WalletKitProvider/context';
import { useEvmIsConnected } from '@/evm/hooks/useEvmIsConnected';
import { useQRCodeUri } from '@/evm/hooks/useQRCodeUri';
import { EvmWallet } from '@/evm/wallets';
import { useCallback, useState } from 'react';

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

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

const wcUri = useQRCodeUri({
onError(error: any) {
if (error.code) {
// https://github.com/MetaMask/eth-rpc-errors/blob/main/src/error-constants.ts
switch (error.code) {
case -32002:
setStatus(CONNECT_STATUS.NOTCONNECTED);
break;
case 4001:
setStatus(CONNECT_STATUS.REJECTED);
break;
default:
setStatus(CONNECT_STATUS.FAILED);
break;
}
} else {
// Sometimes the error doesn't respond with a code
if (error.message) {
switch (error.message) {
case 'User rejected request':
setStatus(CONNECT_STATUS.REJECTED);
break;
default:
setStatus(CONNECT_STATUS.FAILED);
break;
}
}
}
},
});

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

const onClickConnect = useCallback(() => {
setStatus(CONNECT_STATUS.CONNECTING);
window.open(qrCodeUri, '_self', 'noopener noreferrer');
}, [qrCodeUri]);

return (
<ConnectingView
isConnected={isConnected}
status={status}
runConnect={onClickConnect}
wallet={selectedWallet}
isReady={!!wcUri}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,31 +67,43 @@ export function SetEvmWalletClickRef(props: SetEvmWalletClickRefProps) {
jumpTo(ViewRoutes.EVM_CONNECTING);
};

const jumpToWalletConnectView = () => {
jumpTo(ViewRoutes.EVM_CONNECT_WITH_WALLET_CONNECT);
};

disconnect();

clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
if (isWalletConnect(connector.id)) {
if (wallet.showQRCode) {
jumpToQRCodeView();
} else {
if (mobile) {
// 1. mobile
if (isWalletConnect(walletId)) {
wcModal.onOpen();
}
} else if (!wallet.isInstalled()) {
if (mobile) {
} else if (wallet.useWalletConnect) {
jumpToWalletConnectView();
} else if (wallet.isInstalled()) {
jumpToConnectingView();
} else {
const deepLink = wallet.getDeepLink?.();
if (deepLink) {
window.open(deepLink, '_self', 'noopener noreferrer');
} else {
eventConfig.onError?.(new Error('Not supported wallet'), 'Not supported wallet');
}
}
} else {
// 2. pc
if (isWalletConnect(walletId)) {
if (wallet.showQRCode) {
jumpToQRCodeView();
} else {
wcModal.onOpen();
}
} else if (wallet.showQRCode) {
jumpToQRCodeView();
} else {
jumpToConnectingView();
}
} else {
jumpToConnectingView();
}
}, 300);
};
Expand Down
9 changes: 8 additions & 1 deletion packages/walletkit/src/evm/hooks/useQRCodeUri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@ import { useEvmIsConnected } from './useEvmIsConnected';
import { useEventConfig, useLogger } from '@/core/providers/WalletKitProvider/context';
import { evmCommonErrorHandler } from '../utils/evmCommonErrorHandler';
import { getEvmGlobalData } from '../globalData';
import { ConnectErrorType } from 'wagmi/actions';

let timer: any;

export function useQRCodeUri() {
interface UseQRCodeUriProps {
onError?: (error: ConnectErrorType) => void;
}

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

const eventConfig = useEventConfig();
Expand Down Expand Up @@ -38,6 +43,8 @@ export function useQRCodeUri() {
clearTimeout(timer);

timer = setTimeout(() => {
props?.onError?.(error);

if (error?.code === 4001) {
evmCommonErrorHandler({
log,
Expand Down
5 changes: 2 additions & 3 deletions packages/walletkit/src/evm/utils/evmConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import { http, createConfig, CreateConnectorFn, type CreateConfigParameters } fr
import { Chain, mainnet } from 'wagmi/chains';
import { EvmWallet, isWalletConnect, walletConnect } from '@/evm/wallets';
import { Metadata } from '@/core/providers/WalletKitProvider/context';
import { WALLET_CONNECT_PROJECT_ID } from '@/core/configs/getDefaultConfig';
import { WalletType } from '@/core/configs/types';
import { setEvmGlobalData } from '../globalData';

interface CustomizedEvmConfig extends Omit<CreateConfigParameters, 'chains' | 'connectors'> {
autoConnect?: boolean;
metadata?: Metadata;
walletConnectProjectId?: string;
walletConnectProjectId: string;
initialChainId?: number;
wallets: EvmWallet[];
chains?: Chain[];
Expand All @@ -23,7 +22,7 @@ export function evmConfig(params: CustomizedEvmConfig) {
const {
autoConnect = false,
metadata = { name: 'WalletKit' },
walletConnectProjectId = WALLET_CONNECT_PROJECT_ID,
walletConnectProjectId,
initialChainId,
wallets,
chains = [mainnet],
Expand Down
18 changes: 11 additions & 7 deletions packages/walletkit/src/evm/wallets/binanceWeb3Wallet/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { EvmWallet, InjectedEvmWalletOptions } from '../types';
import { injected } from '../injected';
import { isMobile } from '@/core/base/utils/mobile';
import { sleep } from '@/core/utils/common';
import { hasInjectedEvmProvider } from '../utils';
import { getEvmInjectedProvider } from '../utils';

export function binanceWeb3Wallet(props: InjectedEvmWalletOptions = {}): EvmWallet {
const { connectorOptions, ...restProps } = props;
Expand All @@ -13,8 +13,9 @@ export function binanceWeb3Wallet(props: InjectedEvmWalletOptions = {}): EvmWall
id: 'binanceWeb3Wallet',
walletType: 'evm',
showQRCode: true,
useWalletConnect: false,
isInstalled() {
return hasInjectedEvmProvider('isBinance');
return !!getProvider();
},
getDeepLink() {
const url = window.location.href;
Expand All @@ -29,7 +30,7 @@ export function binanceWeb3Wallet(props: InjectedEvmWalletOptions = {}): EvmWall

return deeplink;
},
getQRCodeUri(uri) {
getUri(uri) {
return uri;
},
getCreateConnectorFn() {
Expand All @@ -44,10 +45,8 @@ export function binanceWeb3Wallet(props: InjectedEvmWalletOptions = {}): EvmWall
await sleep();
}
},
async provider(window) {
if (isMobile()) {
return window?.ethereum;
}
async provider() {
return getProvider();
},
},
...connectorOptions,
Expand All @@ -56,3 +55,8 @@ export function binanceWeb3Wallet(props: InjectedEvmWalletOptions = {}): EvmWall
...restProps,
};
}

function getProvider() {
if (typeof window === 'undefined') return;
return getEvmInjectedProvider('isBinance');
}
Loading

0 comments on commit e39f405

Please sign in to comment.