walletconnect 供应商 使用
walletconnect官网有两种用法
本文介绍ethereum providers的使用
1、下载依赖
// npm
$ npm install @walletconnect/ethereum-provider @walletconnect/modal
// pnpm
$ pnpm add @walletconnect/ethereum-provider @walletconnect/modal
2、walletconnect使用
1、申请projectID
官网申请:walletconnect.com
2、引入所需要的依赖
import { ethers } from 'ethers';
import EthereumProvider from '@walletconnect/ethereum-provider';
import {
REQUIRED_METHODS,
REQUIRED_EVENTS,
} from '@walletconnect/ethereum-provider';
3、walletconnect
1、准备配置walletconnect的参数
// 初始化walletconnect需要的参数
const singClientOption = {
logger: 'warn',
relayUrl: 'wss://relay.walletconnect.com',
projectId: PROJECT_ID, // 输入自己的projectID,
showQrModal: true, // 是否显示二维码页面
methods: [...REQUIRED_METHODS, 'eth_signTypedData_v4'],
events: [...REQUIRED_EVENTS],
chains: [56],
optionalChains: [56, 10, 137, 43114, 1],
metadata: {
name: '项目名称',
description: '项目简介',
url: window.location.host, // 项目地址
icons: [`${window.location.origin}/favicon.svg`], // 项目icon
},
};
2、创建walletconnect类
// 没有Provider输出错误
class ProviderNotFoundError extends Error {
constructor() {
super('Not found provider');
}
}
// 是否需要自动连接
interface IConnectorOpt {
autoConnect?: boolean;
}
// class
export class WalletConnectConnector {
#wcProvider?: EthereumProvider;
connectOpt?: IConnectorOpt;
#onDisconnectHandler?: (error: unknown) => void;
#onAccountsChangedHandler?: (accounts: string[]) => void;
#onChainChangedHandler?: (chainId: string) => void;
get provider(): ethers.providers.Web3Provider {
if (!this.#wcProvider) throw new ProviderNotFoundError();
// 构造ethers的providers,方便使用
const provider = new ethers.providers.Web3Provider(this.#wcProvider);
return provider;
}
constructor(opt?: IConnectorOpt) {
this.connectOpt = opt;
this.init(true);
}
// 初始化Provider
async init(reset?: boolean) {
if (reset) {
this.#wcProvider = undefined;
}
if (!this.#wcProvider) {
const provider = await await EthereumProvider.init({
projectId: singClientOption.projectId,
showQrModal: singClientOption.showQrModal,
methods: singClientOption.methods,
events: singClientOption.events,
chains: singClientOption.chains,
optionalChains: singClientOption.optionalChains,
metadata: singClientOption.metadata,
}).then(async (e) => {
this.#wcProvider = e;
return e;
});
return provider;
} else {
return this.#wcProvider;
}
}
// 连接
async connect(reset?: boolean) {
if (!this.connectOpt?.autoConnect) {
reset = true;
}
const provider = await this.init(reset);
const session = await this.isConnected(); // 是否已连接
if (session) {
if (reset) {
try {
await provider.disconnect();
await this.disconnect();
} catch (error) {
console.log(error);
}
}
const [accounts, network] = await Promise.all([
provider.enable(),
Promise.race<ethers.providers.Networkish>([
this.provider.send('eth_chainId', []).then((e) => {
return Number(e);
}),
this.provider.getNetwork().then((e) => e.chainId),
]).then((e) => {
return Number(e);
}),
]);
if (accounts[0]) {
return {
accounts,
provider: new ethers.providers.Web3Provider(provider),
network,
};
}
}
// 默认连接
const isConnected = await Promise.race([
provider
.connect({
chains: [56],
optionalChains: [56, 10, 137, 43114, 1], // 待选链
rpcMap: { // rpc连接
56: 'https://rpc',
10: 'https://rpc',
137: 'https://rpc',
43114: 'https://rpc',
1: 'https://rpc',
},
pairingTopic: reset ? undefined : provider.session?.pairingTopic,
})
.then((e) => {
console.log(e);
return true;
})
.catch((e) => {
console.log(e);
return false;
}),
new Promise((resolve) => {
provider.once(WalletConnectEvents.CONNECT, () => {
resolve(true);
});
provider.modal?.subscribeModal((e: { open: any }) => {
if (!e?.open) resolve(false);
});
}),
]);
if (!isConnected) {
throw Error('Modal Closed, Please try again');
} else {
console.log(isConnected);
const [accounts, network] = await Promise.all([
provider.enable(),
Promise.race<ethers.providers.Networkish>([
this.provider.send('eth_chainId', []).then((e) => {
return Number(e);
}),
this.provider.getNetwork().then((e) => e.chainId),
]).then((e) => {
return Number(e);
}),
]);
if (!accounts[0]) {
throw Error('no account connected');
}
return {
accounts,
provider: new ethers.providers.Web3Provider(provider),
network,
};
}
}
// 断开
async disconnect() {
return await this.#wcProvider?.disconnect();
}
// 是否已连接
async isConnected(): Promise<boolean> {
if (!this.connectOpt?.autoConnect) return false;
if (!this.#wcProvider) {
await this.init();
}
return !!this.#wcProvider?.connected;
}
// 切换链
async switchChain(chainId: ChainIds) {
if (!this.provider) throw new ProviderNotFoundError();
const evmParameter = getEvmChainParameter(chainId);
try {
await this.provider.send('wallet_switchEthereumChain', [{ chainId: evmParameter.chainId }]);
} catch (err: any) {
if (err.code === 4902) {
try {
const evmParameter = getEvmChainParameter(chainId);
await this.addChain(evmParameter);
} catch (err: unknown) {
console.error(err);
}
}
}
}
// 添加chain
async addChain(networkDetails: EvmChainParameter) {
if (!this.provider) throw new ProviderNotFoundError();
try {
this.provider.send('wallet_addEthereumChain', [networkDetails]);
} catch (err: unknown) {
throw Error('wallet_addEthereumChain \n');
}
}
// 监听方法:断开连接时
onDisconnect(handler: (error?: unknown) => void) {
if (!this.#wcProvider) throw new ProviderNotFoundError();
if (this.#onDisconnectHandler) {
this.#wcProvider.removeListener('disconnect', this.#onDisconnectHandler);
this.#wcProvider.removeListener('session_delete', this.#onDisconnectHandler);
}
this.#onDisconnectHandler = handler;
this.#wcProvider.on('disconnect', () => {
handler();
});
this.#wcProvider.on('session_delete', () => {
handler();
});
}
// 监听方法:切换用户时
onAccountsChanged(handler: (accounts: string[]) => void) {
if (!this.#wcProvider) throw new ProviderNotFoundError();
if (this.#onDisconnectHandler) {
this.#wcProvider.removeListener('accountsChanged', this.#onDisconnectHandler);
}
this.#onAccountsChangedHandler = handler;
this.#wcProvider.on('accountsChanged', (accounts: string[]) => {
handler(accounts);
});
}
// 监听方法:切换链时
onChainChanged(handler: (chainId: string) => void) {
if (!this.#wcProvider) throw new ProviderNotFoundError();
if (this.#onChainChangedHandler) {
this.#wcProvider.removeListener('chainChanged', this.#onChainChangedHandler);
}
this.#onChainChangedHandler = handler;
this.#wcProvider!.on('chainChanged', (chainId: string) => {
handler(chainId);
});
}
}
3、使用
// 初始化 WalletConnectConnector
const walletconnect = new WalletConnectConnector();
// 判断是否已经连接
walletconnect?.isConnected()
// 没连接的话,连接
walletconnect?.connect(false).then((e) => {
// ----开始监听
// 切换用户
walletconnect?.onAccountsChanged async (accounts) => {
accounts[0] // 最新连接的用户
});
// 切换链
walletconnect?.onChainChanged(async (chainId) => {
chainId // 切换的链
});
// 断开链接
connector?.onDisconnect(() => {});
return;
})