Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: walletconnect #24

Merged
merged 12 commits into from
Oct 24, 2022
5 changes: 2 additions & 3 deletions packages/wallet-management/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,15 @@
"@ethersproject/experimental": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"@walletconnect/ethereum-provider": "^1.8.0",
"@walletconnect/web3-provider": "^1.8.0",
"@web3-react/coinbase-wallet": "^8.0.34-beta.0",
"@web3-react/core": "^8.0.35-beta.0",
"@web3-react/eip1193": "^8.0.26-beta.0",
"@web3-react/empty": "^8.0.20-beta.0",
"@web3-react/metamask": "^8.0.28-beta.0",
"@web3-react/network": "^8.0.27-beta.0",
"@web3-react/types": "^8.0.20-beta.0",
"@web3-react/url": "^8.0.25-beta.0",
"@web3-react/walletconnect": "^8.0.35-beta.0",
"react": "^18.2.0"
"@web3-react/url": "^8.0.25-beta.0"
},
"eslintConfig": {
"extends": "../../.eslintrc"
Expand Down
96 changes: 85 additions & 11 deletions packages/wallet-management/src/connectors/walletConnect.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,91 @@
import { supportedChains } from '@lifi/sdk';
import { initializeConnector } from '@web3-react/core';
import { WalletConnect } from '@web3-react/walletconnect';
import type { EventEmitter } from 'node:events';

export const [walletConnect, hooks] = initializeConnector<WalletConnect>(
import WalletConnectProvider from '@walletconnect/ethereum-provider';
import type { Actions, RequestArguments } from '@web3-react/types';
import { Connector } from '@web3-react/types';

interface WalletConnectOptions {
rpc: {
[chainId: number]: string;
};
}

interface MockWalletConnectProvider
extends Omit<WalletConnectProvider, 'on' | 'off' | 'once' | 'removeListener'>,
EventEmitter {}

class WalletConnectV2 extends Connector {
private readonly options?: WalletConnectOptions;

public provider: MockWalletConnectProvider;

public walletConnectProvider: WalletConnectProvider;

public isCurrentlyUsed: boolean = false;

constructor(actions: Actions, options?: WalletConnectOptions) {
super(actions);
this.options = options;

const walletConnectProvider = new WalletConnectProvider({
rpc: this.options!.rpc,
});
this.provider =
walletConnectProvider as unknown as MockWalletConnectProvider;
this.walletConnectProvider = walletConnectProvider;
}

private async startListening(): Promise<void> {
// Subscribe to accounts change
this.provider?.on('accountsChanged', (accounts: string[]) => {
this.actions.update({ accounts });
});

// Subscribe to chainId change
this.provider?.on('chainChanged', (chainId: number) => {
this.actions.update({ chainId });
});

// Subscribe to session disconnection
this.provider?.on('disconnect', (code: number, reason: string) => {
this.actions.update({ accounts: [], chainId: undefined });
this.actions.resetState();
this.isCurrentlyUsed = false;
});
}

public connectEagerly = () => {};

public async activate(): Promise<void> {
this.actions.startActivation();
this.isCurrentlyUsed = true;

await this.provider?.enable(); // open modal
this.startListening();

this.actions.update({ accounts: this.provider.accounts });

this.actions.update({ chainId: this.provider.chainId });
}

public async deactivate(): Promise<void> {
if (this.provider) {
await this.provider?.disconnect();
this.isCurrentlyUsed = false;
this.actions.resetState();
}
}
}

export const [walletConnect, hooks] = initializeConnector<WalletConnectV2>(
(actions) =>
new WalletConnect({
actions,
options: {
rpc: Object.fromEntries(
supportedChains.map((chain) => {
return [chain.id, chain.metamask.rpcUrls[0] || ''];
}),
),
},
new WalletConnectV2(actions, {
rpc: Object.fromEntries(
supportedChains.map((chain) => {
return [chain.id, chain.metamask.rpcUrls[0] || ''];
}),
),
}),
);
2 changes: 1 addition & 1 deletion packages/wallet-management/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './LiFiWalletManagement';
export * from './wallets';
export * from './browserWallets';
export * from './walletAutomation';
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
/* eslint-disable radix */
import type { Token } from '@lifi/sdk';
import {
getChainById,
MetaMaskProviderErrorCode,
prefixChainId,
} from '@lifi/sdk';
import type { Token } from '@lifi/sdk';
import { walletConnect } from './connectors/walletConnect';
/* eslint-disable radix */

export const switchChain = async (chainId: number): Promise<boolean> => {
return new Promise((resolve, reject) => {
const { ethereum } = window as any;
if (!ethereum) resolve(false);

let provider: any;
if (walletConnect.isCurrentlyUsed) {
provider = walletConnect.walletConnectProvider;
} else {
const { ethereum } = window as any;
provider = ethereum;
}
if (!provider) {
resolve(false);
}
try {
ethereum
provider
.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: getChainById(chainId).metamask?.chainId }],
Expand All @@ -24,7 +32,7 @@ export const switchChain = async (chainId: number): Promise<boolean> => {
reject(error);
}
});
ethereum.once('chainChanged', (id: string) => {
provider.once('chainChanged', (id: string) => {
if (parseInt(id) === chainId) {
resolve(true);
}
Expand All @@ -34,19 +42,28 @@ export const switchChain = async (chainId: number): Promise<boolean> => {
if (error.code !== MetaMaskProviderErrorCode.userRejectedRequest) {
addChain(chainId).then((result) => resolve(result));
} else {
console.error(error);
resolve(false);
}
}
});
};

export const addChain = async (chainId: number) => {
const { ethereum } = window as any;
if (typeof ethereum === 'undefined') return false;
let provider: any;
if (walletConnect.isCurrentlyUsed) {
provider = walletConnect.walletConnectProvider;
} else {
const { ethereum } = window as any;
provider = ethereum;
}
if (!provider) {
return false;
}

const params = getChainById(chainId).metamask;
try {
await ethereum.request({
await provider.request({
method: 'wallet_addEthereumChain',
params: [params],
});
Expand All @@ -58,9 +75,19 @@ export const addChain = async (chainId: number) => {
};

export const addToken = async (token: Token) => {
let provider: any;
if (walletConnect.isCurrentlyUsed) {
provider = walletConnect.walletConnectProvider;
} else {
const { ethereum } = window as any;
provider = ethereum;
}
if (!provider) {
return false;
}
try {
// wasAdded is a boolean. Like any RPC method, an error may be thrown.
const wasAdded = await (window as any).ethereum.request({
const wasAdded = await provider.request({
method: 'wallet_watchAsset',
params: {
type: 'ERC20', // Initially only supports ERC20, but eventually more!
Expand All @@ -80,12 +107,21 @@ export const addToken = async (token: Token) => {
};

export const switchChainAndAddToken = async (chainId: number, token: Token) => {
const { ethereum } = window as any;
let provider: any;
if (walletConnect.isCurrentlyUsed) {
provider = walletConnect.walletConnectProvider;
} else {
const { ethereum } = window as any;
provider = ethereum;
}
if (!provider) {
return;
}
const chainIdPrefixed = prefixChainId(chainId);

if (chainIdPrefixed !== ethereum.chainId) {
if (chainIdPrefixed !== provider.chainId) {
await switchChain(chainId);
ethereum.once('chainChanged', async (id: string) => {
provider.once('chainChanged', async (id: string) => {
if (parseInt(id, 10) === chainId) {
await addToken(token);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/wallet-management/src/walletIcons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ import walletio from './walletio.svg';
import tp from './tp.svg';
import xdefi from './xdefi.svg';
import mathwallet from './mathWallet.svg';
import walletConnect from './walletConnect.svg';

export const walletIcons = {
mathwallet,
walletConnect,
alphawallet,
atoken,
blockwallet,
Expand Down
11 changes: 11 additions & 0 deletions packages/wallet-management/src/wallets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Connector } from '@web3-react/types';
import { metaMask } from './connectors/metaMask';
import { walletIcons } from './walletIcons';
import { walletConnect as walletConnectConnector } from './connectors/walletConnect';

export interface Wallet {
name: string;
Expand Down Expand Up @@ -43,6 +44,7 @@ enum ProviderIdentityFlag {
Tokenary = 'isTokenary',
MathWallet = 'isMathWallet',
}

const metamask: Wallet = {
name: 'MetaMask',
checkProviderIdentity: ({ provider }) =>
Expand All @@ -54,6 +56,14 @@ const metamask: Wallet = {
platforms: ['all'],
};

const walletConnect: Wallet = {
name: 'Wallet Connect',
checkProviderIdentity: ({ provider }) => true,
icon: walletIcons.walletConnect,
connector: walletConnectConnector,
platforms: ['all'],
};

const brave: Wallet = {
name: 'Brave',
checkProviderIdentity: ({ provider }) =>
Expand Down Expand Up @@ -299,6 +309,7 @@ const tokenary: Wallet = {

export const supportedWallets = [
metamask,
walletConnect,
binance,
coinbase,
detected,
Expand Down
Loading