Skip to content

Commit

Permalink
WIP feat: init WalletConnect V2 (#1726)
Browse files Browse the repository at this point in the history
* feat: init v2

* fix: chainId

* fix: chainId

* fix: qrcode

* fix: update
  • Loading branch information
heisenberg-2077 authored Sep 15, 2023
1 parent 9ed0466 commit 7713dcc
Show file tree
Hide file tree
Showing 17 changed files with 642 additions and 396 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@rabby-wallet/eth-lattice-keyring": "^1.0.5",
"@rabby-wallet/eth-simple-keyring": "^4.2.1",
"@rabby-wallet/eth-trezor-keyring": "^2.2.0",
"@rabby-wallet/eth-walletconnect-keyring": "^1.7.21",
"@rabby-wallet/eth-walletconnect-keyring": "2.0.0-beta.5",
"@rabby-wallet/eth-watch-keyring": "^1.0.0",
"@rabby-wallet/gnosis-sdk": "^1.3.5",
"@rabby-wallet/page-provider": "^0.1.20",
Expand Down
111 changes: 48 additions & 63 deletions src/background/controller/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Wallet, { thirdparty } from 'ethereumjs-wallet';
import { ethErrors } from 'eth-rpc-errors';
import * as bip39 from 'bip39';
import { ethers, Contract } from 'ethers';
import { groupBy, uniq } from 'lodash';
import { chain, groupBy, uniq } from 'lodash';
import abiCoder, { AbiCoder } from 'web3-eth-abi';
import * as optimismContracts from '@eth-optimism/contracts';
import {
Expand Down Expand Up @@ -60,7 +60,7 @@ import {
} from '@rabby-wallet/rabby-security-engine/dist/rules';
import DisplayKeyring from '../service/keyring/display';
import provider from './provider';
import WalletConnectKeyring from '@rabby-wallet/eth-walletconnect-keyring';
import { WalletConnectKeyring } from '@rabby-wallet/eth-walletconnect-keyring';
import eventBus from '@/eventBus';
import {
setPageStateCacheWhenPopupClose,
Expand Down Expand Up @@ -98,6 +98,7 @@ import { t } from 'i18next';
import { getWeb3Provider } from './utils';
import { CoboSafeAccount } from '@/utils/cobo-agrus-sdk/cobo-agrus-sdk';
import CoboArgusKeyring from '../service/keyring/eth-cobo-argus-keyring';
import { GET_WALLETCONNECT_CONFIG } from '@/utils/walletconnect';

const stashKeyrings: Record<string | number, any> = {};

Expand Down Expand Up @@ -1709,7 +1710,11 @@ export class WalletController extends BaseController {
return null;
};

initWalletConnect = async (brandName: string, curStashId?: number | null) => {
initWalletConnect = async (
brandName: string,
curStashId?: number | null,
chainId = 1
) => {
let keyring: WalletConnectKeyring, isNewKey;
const keyringType = KEYRING_CLASS.WALLETCONNECT;
try {
Expand All @@ -1721,28 +1726,24 @@ export class WalletController extends BaseController {
}
} catch {
const WalletConnect = keyringService.getKeyringClassForType(keyringType);
keyring = new WalletConnect({
accounts: [],
brandName: brandName,
// 1h
maxDuration: 3600000,
clientMeta: {
description: t('global.appDescription'),
url: 'https://rabby.io',
icons: ['https://rabby.io/assets/images/logo.png'],
name: 'Rabby',
},
});
keyring = new WalletConnect(GET_WALLETCONNECT_CONFIG());
isNewKey = true;
}
const { uri } = await keyring.initConnector(brandName);
const { uri } = await keyring.initConnector(
brandName,
!chainId ? 1 : chainId
);
let stashId = curStashId;
if (isNewKey) {
stashId = this.addKeyringToStash(keyring);
eventBus.addEventListener(
EVENTS.WALLETCONNECT.INIT,
({ address, brandName }) => {
(keyring as WalletConnectKeyring).init(address, brandName);
({ address, brandName, chainId }) => {
(keyring as WalletConnectKeyring).init(
address,
brandName,
!chainId ? 1 : chainId
);
}
);
(keyring as WalletConnectKeyring).on('inited', (uri) => {
Expand Down Expand Up @@ -1797,40 +1798,6 @@ export class WalletController extends BaseController {
};
};

getWalletConnectBridge = (address: string, brandName: string) => {
const keyringType = KEYRING_CLASS.WALLETCONNECT;
const keyring: WalletConnectKeyring = this._getKeyringByType(keyringType);
if (keyring) {
const target = keyring.accounts.find(
(account) =>
account.address.toLowerCase() === address.toLowerCase() &&
brandName === account.brandName
);

if (target) return target.bridge;

return null;
}
return null;
};

getWalletConnectConnectors = () => {
const keyringType = KEYRING_CLASS.WALLETCONNECT;
const keyring: WalletConnectKeyring = this._getKeyringByType(keyringType);
if (keyring) {
const result: { address: string; brandName: string }[] = [];
for (const key in keyring.connectors) {
const target = keyring.connectors[key];
result.push({
address: key.split('-')[1],
brandName: target.brandName,
});
}
return result;
}
return [];
};

killWalletConnectConnector = async (
address: string,
brandName: string,
Expand All @@ -1840,17 +1807,11 @@ export class WalletController extends BaseController {
const keyringType = KEYRING_CLASS.WALLETCONNECT;
const keyring: WalletConnectKeyring = this._getKeyringByType(keyringType);
if (keyring) {
const connector =
keyring.connectors[`${brandName}-${address.toLowerCase()}`];
if (connector) {
await keyring.closeConnector(
connector.connector,
address,
brandName,
silent
);
const topic = keyring.cached.findTopic({ address, brandName });
if (topic) {
await keyring.closeConnector({ topic }, silent);
// reset onAfterConnect
if (resetConnect) keyring.onAfterConnect = null;
if (resetConnect) keyring.onAfterSessionCreated = undefined;
}
}
};
Expand Down Expand Up @@ -1892,7 +1853,6 @@ export class WalletController extends BaseController {
keyring.setAccountToAdd({
address,
brandName,
bridge,
realBrandName,
realBrandUrl,
});
Expand Down Expand Up @@ -3293,6 +3253,31 @@ export class WalletController extends BaseController {
isModuleEnabled,
};
};

walletConnectScanAccount = async () => {
let keyring: WalletConnectKeyring, isNewKey;
const keyringType = KEYRING_CLASS.WALLETCONNECT;
try {
keyring = this._getKeyringByType(keyringType);
} catch {
const WalletConnect = keyringService.getKeyringClassForType(keyringType);
keyring = new WalletConnect(GET_WALLETCONNECT_CONFIG());
isNewKey = true;
}

if (isNewKey) {
this.addKeyringToStash(keyring);
}

keyring.on('scanAccount', (payload) => {
eventBus.emit(EVENTS.broadcastToUI, {
method: EVENTS.WALLETCONNECT.SCAN_ACCOUNT,
params: payload,
});
});

return await keyring.scanAccount();
};
}

const wallet = new WalletController();
Expand Down
18 changes: 12 additions & 6 deletions src/background/service/keyring/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ import LatticeKeyring from './eth-lattice-keyring';
import WatchKeyring from '@rabby-wallet/eth-watch-keyring';
import KeystoneKeyring from './eth-keystone-keyring';
import CoboArgusKeyring from './eth-cobo-argus-keyring';
import WalletConnectKeyring, {
keyringType,
} from '@rabby-wallet/eth-walletconnect-keyring';
import { WalletConnectKeyring } from '@rabby-wallet/eth-walletconnect-keyring';
import GnosisKeyring, {
TransactionBuiltEvent,
TransactionConfirmedEvent,
Expand All @@ -37,6 +35,7 @@ import { isSameAddress } from 'background/utils';
import contactBook from '../contactBook';
import { generateAliasName } from '@/utils/account';
import * as Sentry from '@sentry/browser';
import { GET_WALLETCONNECT_CONFIG } from '@/utils/walletconnect';

export const KEYRING_SDK_TYPES = {
SimpleKeyring,
Expand Down Expand Up @@ -859,7 +858,10 @@ export class KeyringService extends EventEmitter {
async _restoreKeyring(serialized: any): Promise<any> {
const { type, data } = serialized;
const Keyring = this.getKeyringClassForType(type);
const keyring = new Keyring();
const keyring =
Keyring?.type === KEYRING_CLASS.WALLETCONNECT
? new Keyring(GET_WALLETCONNECT_CONFIG())
: new Keyring();
await keyring.deserialize(data);
if (
keyring.type === HARDWARE_KEYRING_TYPES.Ledger.type &&
Expand All @@ -870,8 +872,12 @@ export class KeyringService extends EventEmitter {
if (keyring.type === KEYRING_CLASS.WALLETCONNECT) {
eventBus.addEventListener(
EVENTS.WALLETCONNECT.INIT,
({ address, brandName }) => {
(keyring as WalletConnectKeyring).init(address, brandName);
({ address, brandName, chainId }) => {
(keyring as WalletConnectKeyring).init(
address,
brandName,
!chainId ? 1 : chainId
);
}
);
(keyring as WalletConnectKeyring).on('inited', (uri) => {
Expand Down
1 change: 1 addition & 0 deletions src/constant/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ export const EVENTS = {
INIT: 'WALLETCONNECT_INIT',
INITED: 'WALLETCONNECT_INITED',
TRANSPORT_ERROR: 'TRANSPORT_ERROR',
SCAN_ACCOUNT: 'SCAN_ACCOUNT',
},
GNOSIS: {
TX_BUILT: 'TransactionBuilt',
Expand Down
34 changes: 14 additions & 20 deletions src/ui/component/ScanCopyQRCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ import IconRefresh from 'ui/assets/urlrefresh.svg';
import { ConnectStatus } from './WalletConnect/ConnectStatus';
import { useSessionStatus } from './WalletConnect/useSessionStatus';
import { Account } from '@/background/service/preference';
import Spin from './Spin';

interface Props {
showURL: boolean;
changeShowURL: (active: boolean) => void;
refreshFun(): void;
qrcodeURL: string;
onBridgeChange(val: string): void;
bridgeURL: string;
defaultBridge: string;
canChangeBridge?: boolean;
brandName?: string;
account?: Account;
Expand All @@ -31,9 +29,6 @@ const ScanCopyQRCode: React.FC<Props> = ({
changeShowURL,
qrcodeURL,
refreshFun,
onBridgeChange,
bridgeURL,
defaultBridge,
canChangeBridge = true,
brandName,
account,
Expand Down Expand Up @@ -69,11 +64,6 @@ const ScanCopyQRCode: React.FC<Props> = ({
});
};

const handleBridgeServerChange = (val: string) => {
onBridgeChange(val);
setShowOpenApiModal(false);
};

React.useEffect(() => {
// refresh when status is not connected
if (status && status !== 'CONNECTED') {
Expand All @@ -98,8 +88,19 @@ const ScanCopyQRCode: React.FC<Props> = ({
</div>
</div>
{!showURL && (
<div className="qrcode mb-0" {...hoverProps}>
<QRCode value={qrcodeURL} size={170} />
<div className="qrcode mb-0 relative" {...hoverProps}>
{!qrcodeURL ? (
<div
className={clsx(
'bg-white bg-opacity-70 absolute inset-0',
'flex items-center justify-center'
)}
>
<Spin />
</div>
) : (
<QRCode value={qrcodeURL} size={170} />
)}
{isHovering && (
<div className="refresh-container">
<div className="refresh-wrapper">
Expand Down Expand Up @@ -145,13 +146,6 @@ const ScanCopyQRCode: React.FC<Props> = ({
{t('page.newAddress.walletConnect.changeBridgeServer')}
</div>
)}
<WalletConnectBridgeModal
defaultValue={defaultBridge}
value={bridgeURL}
visible={showOpenApiModal}
onChange={handleBridgeServerChange}
onCancel={() => setShowOpenApiModal(false)}
/>
<ConnectStatus account={account} uri={qrcodeURL} brandName={brandName} />
</div>
);
Expand Down
10 changes: 0 additions & 10 deletions src/ui/component/WalletConnect/ReconnectView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { EVENTS, KEYRING_CLASS } from '@/constant';
import eventBus from '@/eventBus';
import { noop, useCommonPopupView, useWallet } from '@/ui/utils';
import { DEFAULT_BRIDGE } from '@rabby-wallet/eth-walletconnect-keyring';
import React from 'react';
import { Account } from 'background/service/preference';
import Scan from '@/ui/views/Approval/components/WatchAddressWaiting/Scan';
Expand All @@ -25,7 +24,6 @@ export const ReconnectView: React.FC = () => {
null
);
const { status, errorAccount } = useSessionStatus(account);
const [bridgeURL, setBridge] = React.useState<string>(DEFAULT_BRIDGE);
const [displayBrandName] = useDisplayBrandName(
account?.realBrandName || account?.brandName
);
Expand Down Expand Up @@ -55,16 +53,11 @@ export const ReconnectView: React.FC = () => {

const init = async () => {
if (!account) return;
const bridge = await wallet.getWalletConnectBridge(
account.address,
account.brandName
);
setCurrentAccount({
...account,
brandName: account.realBrandName || account.brandName,
type: KEYRING_CLASS.WALLETCONNECT,
});
setBridge(bridge || DEFAULT_BRIDGE);
setPopupViewTitle(
t('page.newAddress.walletConnect.title', { brandName: displayBrandName })
);
Expand Down Expand Up @@ -105,11 +98,8 @@ export const ReconnectView: React.FC = () => {
{currentAccount && visible && (
<Scan
uri={qrCodeContent}
bridgeURL={bridgeURL}
onRefresh={handleRefreshQrCode}
defaultBridge={DEFAULT_BRIDGE}
account={currentAccount}
onBridgeChange={noop}
/>
)}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/ui/component/WalletConnect/useSessionStatus.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EVENTS, WALLET_BRAND_TYPES } from '@/constant';
import eventBus from '@/eventBus';
import { isSameAddress, useWallet } from '@/ui/utils';
import { WALLETCONNECT_SESSION_STATUS_MAP } from '@rabby-wallet/eth-walletconnect-keyring';
import { WALLETCONNECT_SESSION_STATUS_MAP } from '@rabby-wallet/eth-walletconnect-keyring/dist/type';
import React from 'react';

type Status = keyof typeof WALLETCONNECT_SESSION_STATUS_MAP;
Expand Down
6 changes: 1 addition & 5 deletions src/ui/component/WalletConnectBridgeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ import { useMedia } from 'react-use';

const OpenApiModal = ({
value,
defaultValue,
visible,
onChange,
onCancel,
}: {
value: string;
defaultValue: string;
visible: boolean;
onChange(val: string): void;
onCancel(): void;
Expand All @@ -36,9 +34,7 @@ const OpenApiModal = ({
};

const restoreInitial = () => {
form.setFieldsValue({
host: defaultValue,
});
form.setFieldsValue({});
};

useEffect(() => {
Expand Down
Loading

0 comments on commit 7713dcc

Please sign in to comment.