Skip to content

Commit

Permalink
feat: walletconnect (#24)
Browse files Browse the repository at this point in the history
* feat: walletconnect

* feat: upgrade to wallet connect v2

* fix: formatting

* fix: dependencies

* chore: remove unused dependencies

* chore: push lock

* refactor: rename file

* feat: added walletautomations for walletconnect

* fix: linting

* chore: sort imports

Co-authored-by: Eugene Chybisov <imchybisov@gmail.com>
  • Loading branch information
Addminus and chybisov authored Oct 24, 2022
1 parent e0b5bdb commit b3e7bcf
Show file tree
Hide file tree
Showing 7 changed files with 1,253 additions and 58 deletions.
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
95 changes: 84 additions & 11 deletions packages/wallet-management/src/connectors/walletConnect.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,90 @@
import { supportedChains } from '@lifi/sdk';
import WalletConnectProvider from '@walletconnect/ethereum-provider';
import { initializeConnector } from '@web3-react/core';
import { WalletConnect } from '@web3-react/walletconnect';
import type { Actions } from '@web3-react/types';
import { Connector } from '@web3-react/types';
import type { EventEmitter } from 'node:events';

export const [walletConnect, hooks] = initializeConnector<WalletConnect>(
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 './walletAutomation';
export * from './wallets';
export * from './browserWallets';
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@ import {
MetaMaskProviderErrorCode,
prefixChainId,
} from '@lifi/sdk';
import { walletConnect } from './connectors/walletConnect';

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

0 comments on commit b3e7bcf

Please sign in to comment.