Skip to content

Commit

Permalink
fix: handle switch network flow for wallet-connect
Browse files Browse the repository at this point in the history
  • Loading branch information
RanGojo committed Nov 12, 2023
1 parent 4b27c10 commit f60f65a
Show file tree
Hide file tree
Showing 10 changed files with 344 additions and 89 deletions.
2 changes: 2 additions & 0 deletions wallets/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export type SwitchNetwork = (options: {
network: Network;
meta: BlockchainMeta[];
newInstance?: TryGetInstance;
getState?: () => WalletState;
}) => Promise<void>;

export type Suggest = (options: {
Expand Down Expand Up @@ -121,6 +122,7 @@ export interface WalletConfig {
defaultNetwork?: Network;
checkInstallation?: boolean;
isAsyncInstance?: boolean;
isAsyncSwitchNetwork?: boolean;
}

export type WalletProviders = Map<
Expand Down
17 changes: 13 additions & 4 deletions wallets/core/src/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ export interface Options {
}

class Wallet<InstanceType = any> {
public provider: InstanceType | null;
private actions: WalletActions;
private state: State;
private options: Options;
private meta: BlockchainMeta[];
public provider: InstanceType | null;

constructor(options: Options, actions: WalletActions) {
this.actions = actions;
Expand Down Expand Up @@ -109,10 +109,18 @@ class Wallet<InstanceType = any> {
// @ts-ignore
network: requestedNetwork,
newInstance: this.tryGetInstance.bind(this),
getState: this.getState.bind(this),
});

// We assume if we reach here (`switchNetwork` not throwing error), Switch successfully has been done.
if (requestedNetwork !== this.state.network) {
/*
* We assume if we reach here (`switchNetwork` not throwing error), Switch successfully has been done.
* But for providers with async switch network like wallet-connect, we need to wait for chain change
* event before changing network.
*/
if (
requestedNetwork !== this.state.network &&
!this.options.config.isAsyncSwitchNetwork
) {
this.updateState({
network,
});
Expand Down Expand Up @@ -205,7 +213,7 @@ class Wallet<InstanceType = any> {
this.resetState();

if (this.actions.disconnect) {
this.actions.disconnect({
void this.actions.disconnect({
instance: this.provider,
// On wallet connect, we need to destory the instance and get a whole new instance when we are going to connect
destroyInstance: () => {
Expand Down Expand Up @@ -403,6 +411,7 @@ class Wallet<InstanceType = any> {
installed: value,
});
}
// eslint-disable-next-line destructuring/in-methods-params
private async tryGetInstance({
network,
force,
Expand Down
8 changes: 4 additions & 4 deletions wallets/provider-walletconnect-2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@
"@rango-dev/wallets-shared": "^0.17.1-next.1",
"@solana/web3.js": "^1.67.2",
"@walletconnect/encoding": "^1.0.2",
"@walletconnect/modal": "^2.6.1",
"@walletconnect/sign-client": "^2.9.1",
"@walletconnect/utils": "^2.9.1",
"@walletconnect/modal": "^2.6.2",
"@walletconnect/sign-client": "^2.10.4",
"@walletconnect/utils": "^2.10.4",
"bs58": "^5.0.0",
"caip": "^1.1.0",
"cosmos-wallet": "^1.2.0",
"rango-types": "^0.1.47"
},
"devDependencies": {
"@walletconnect/types": "^2.9.1"
"@walletconnect/types": "^2.10.4"
},
"publishConfig": {
"access": "public"
Expand Down
15 changes: 12 additions & 3 deletions wallets/provider-walletconnect-2/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export enum NAMESPACES {
MULTIVERSX = 'multiversx',
}

export const CHAIN_ID_STORAGE = 'wc@2:client//namespaces';

// Refrence: https://docs.walletconnect.com/2.0/advanced/rpc-reference/solana-rpc
export enum SolanaRPCMethods {
GET_ACCOUNTS = 'solana_getAccounts',
Expand All @@ -36,6 +38,9 @@ export enum EthereumRPCMethods {
SIGN_TRANSACTION = 'eth_signTransaction',
SEND_TRANSACTION = 'eth_sendTransaction',
SEND_RAW_TRANSACTION = 'eth_sendRawTransaction',
SWITCH_CHAIN = 'wallet_switchEthereumChain',
ADD_CHAIN = 'wallet_addEthereumChain',
GET_CHAIN = 'eth_chainId',
}

export enum StarknetRPCMethods {
Expand All @@ -57,11 +62,16 @@ export const DEFAULT_ETHEREUM_METHODS = [
EthereumRPCMethods.PERSONAL_SIGN,
EthereumRPCMethods.SEND_TRANSACTION,
EthereumRPCMethods.SIGN_TRANSACTION,
EthereumRPCMethods.SWITCH_CHAIN,
EthereumRPCMethods.ADD_CHAIN,
EthereumRPCMethods.GET_CHAIN,
];

export const DEFAULT_SOLANA_METHODS = [
SolanaRPCMethods.SIGN_TRANSACTION,
SolanaRPCMethods.SIGN_MESSAGE,
];

export const DEFAULT_COSMOS_METHODS = [
CosmosRPCMethods.GET_ACCOUNTS,
CosmosRPCMethods.SIGN_AMINO,
Expand All @@ -73,10 +83,9 @@ export const DEFAULT_SOLANA_CHAIN_ID = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';

export const DEFAULT_APP_METADATA = {
name: 'Rango Exchange',
description:
'Easiest DEX UX with best price to exchange all coins on all blockchains.',
description: 'The Ultimate Cross-Chain Solution',
url: 'https://app.rango.exchange/',
icons: ['https://avatars.githubusercontent.com/u/37784886'],
icons: ['https://app.rango.exchange/logo-rounded.png'],
};

export const RELAY_URL = 'wss://relay.walletconnect.com';
96 changes: 93 additions & 3 deletions wallets/provider-walletconnect-2/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,26 @@ import type { WalletState } from '@rango-dev/wallets-shared';
import type { ProposalTypes } from '@walletconnect/types';
import type { BlockchainMeta } from 'rango-types';

import { Networks } from '@rango-dev/wallets-shared';
import {
convertEvmBlockchainMetaToEvmChainInfo,
isEvmAddress,
Networks,
} from '@rango-dev/wallets-shared';
import { WalletConnectModal } from '@walletconnect/modal';
import { ChainId } from 'caip';
import { cosmosBlockchains, evmBlockchains } from 'rango-types';
import { AccountId, ChainId } from 'caip';
import {
cosmosBlockchains,
evmBlockchains,
isEvmBlockchain,
} from 'rango-types';

import {
DEFAULT_COSMOS_METHODS,
DEFAULT_ETHEREUM_EVENTS,
DEFAULT_ETHEREUM_METHODS,
DEFAULT_SOLANA_CHAIN_ID,
DEFAULT_SOLANA_METHODS,
EthereumRPCMethods,
NAMESPACES,
} from './constants';
import { getLastSession } from './session';
Expand Down Expand Up @@ -192,3 +201,84 @@ export function getChainIdByNetworkName(

return chainId;
}

export async function switchOrAddEvmChain(
meta: BlockchainMeta[],
requestedNetwork: string,
currentNetwork: string,
instance: any
) {
const evmBlockchains = meta.filter(isEvmBlockchain);
const evmNetworksChainInfo =
convertEvmBlockchainMetaToEvmChainInfo(evmBlockchains);
const targetChain = evmNetworksChainInfo[requestedNetwork];
const targetBlockchain = meta.find(
(blockchain: BlockchainMeta) => blockchain.name === requestedNetwork
);
const chainIdInHex = targetBlockchain?.chainId;

const currentChainId = getChainIdByNetworkName(currentNetwork, meta);
const currentChainEip = ChainId.format({
namespace: NAMESPACES.ETHEREUM,
reference: String(currentChainId),
});

const session = instance.session;

try {
await instance.client.request({
topic: session.topic,
request: {
method: EthereumRPCMethods.SWITCH_CHAIN,
params: [
{
chainId: chainIdInHex,
},
],
},
// It's required to pass current chain, otherwise it won't work
chainId: currentChainEip,
});
} catch (err: any) {
const addChainError = 4902;
if (
err?.code === addChainError ||
err?.message?.includes(String(addChainError))
) {
await instance.client.request({
topic: session.topic,
request: {
method: EthereumRPCMethods.ADD_CHAIN,
params: [targetChain],
},
// It's required to pass current chain, otherwise it won't work
chainId: currentChainEip,
});
} else {
throw err;
}
}
}

export function getCurrentEvmAccountAddress(instance: any) {
return instance.session.namespaces.eip155.accounts
?.map((account: string) => {
return new AccountId(account).address;
})
?.filter((address: string) => isEvmAddress(address))?.[0];
}

export function getEvmAccount(
network: string,
address: string,
meta: BlockchainMeta[]
) {
const currentChainId = getChainIdByNetworkName(network, meta);
return AccountId.format({
chainId: {
namespace: NAMESPACES.ETHEREUM,
reference: String(currentChainId),
},
address,
});
}
Loading

0 comments on commit f60f65a

Please sign in to comment.