RainbowKitV1.0.3新版本,变动很大,也很稳定
一、前言
端午放假回来,忽然发现很多在用的网站或者工具都进行了大版本更新,其中包括github
的新版本UI出现(非常不适应),figma
大更新,可以切换为开发模式或者设计模式,而目前使用的dapp
连接工具Rainbowkit
也迎来了V1.0.3版本。
话不多说,进入正题,其实RainbowkitV1
版本的更新已经有一段时间的了吧,但是在刚刚发布的V1版本中,YaSol测试发现还是不稳定的,有很多rainbowkit
和wagmi
版本适配问题没有做好,所以就选择了继续使用0.11
,但是这次更新到v1.0.3
后决定再试一下,看看有没有好一些了,测试发现之前1.0版本的适配问题,在1.0.3版本中没有出现,所以这次决定将项目中的Rainbowkit
更新为最新版本。
二、更新后的感受
将项目中的Rainbowkit
更新为最新版后,最直观的感受就是切链的时候不会再断开了,在使用v0.11版本的时候,经常一切链,项目中的连接状态就断开了,但是更新了新版本之后发现在切链的时候任然可以保持连接状态。
项目中目前是使用
useAccount
里面的isDisconnecteds
来判断的
其次就是好像与链上交互的稳定性有了提升。目前来说,感觉还是很支持升级的。
三、配置变动
新版rainbowkit的config是有变动的,所以在更新的时候,需要注意配置的更新
3.1、config变动
1、configureChains不再返回 provider
,webSocketProvider
2、getDefaultWallets需要添加一个projectId
,这个id可以直接在WalletConnect网站申请
3、v0.11版本是createClient
,而在V1.0.3版本中是createConfig
//v0.11 configureChains
const {chains, provider, webSocketProvider} = configureChains(
[mainnet, polygon, goerli,polygonMumbai],
[publicProvider()],
);
//v1.0.3 configureChains
export const { chains, publicClient } = configureChains(
[mainnet, polygon, goerli,polygonMumbai],
[publicProvider()]
);
//v0.11 getDefaultWallets
const {connectors} = getDefaultWallets({
appName: "YaSol",
chains,
});
//v1.0.3 getDefaultWallets
const { connectors } = getDefaultWallets({
appName: 'YaSol',
projectId: '6175672e3657ffXXXXXa0ddd3573bc745', // 新增WalletConnect的projectId
chains
});
//v0.11 createClient
export const wagmiClient = createClient({
autoConnect: true,
connectors,
provider,
webSocketProvider,
});
//v1.0.3 createConfig
export const wagmiConfig = createConfig({
autoConnect: true,
connectors,
publicClient
})
3.2、全局包裹的Provider变动
//v0.11版本的provider
<WagmiConfig client={wagmiClient}>
<RainbowKitProvider chains={chains}>
{children}
</RainbowKitProvider>
</WagmiConfig>
// v1.03版本的provider
<WagmiConfig config={wagmiConfig}>
<RainbowKitProvider chains={chains}>
{children}
</RainbowKitProvider>
</WagmiConfig>
通过上述配置文件的更新之后,你的网站基础rainbowkit就更新完啦🎉
四、获取provider实例的变动
因为新版的Rainbowkit
使用了最新版的Wagmi
,而最新版的Wagmi
剔除了对ethers.js
的依赖,而转向了Viem
。因此如果在项目中我们有使用到ethers
的provider
时,我们就需要注意本次的更新。
//旧版的获取
const {data: signer, isLoading: signerLoadig, isError: signerError} = useSigner();
const web3 = new Web3((signer?.provider as any).provider);
但是我们在Wagmi
的更新日志中可以发现,新版的Wagmi
已经移除了useSigner
或者fetchSigner
的用法,改成了useWalletClient
和getWalletClient
,但是在更新日志中说了这么一句话
The
getSigner
method has been renamed togetWalletClient
, and also returns viem'sWalletClient
instead of an Ethers.jsSigner
大概意思就是说,你通过getWalletClient
或者useWalletClient
返回的是 viem 的 Wallet Client 而不是 Ethers.js Signer
,那我们项目中需要用到Ethers.js的provider
咋办,别慌,我们认真看一下wagmi的官网wagmi.sh/react/ether…
在官网侧边的最下方,有一个Ethers.js Adapters
,这个就是Wagmi
在切换到viem
后,考虑到可能有些项目任然需要使用ethers
的provider
,所以特意添加了这个Ethers.js
的适配器。在适配器里面有获取ethers
的provider
和signer
的解决方案。
4.1如果你需要获取ethers.js V5
的jsonRpcProvider
即
import * as React from 'react'
import { type PublicClient, usePublicClient } from 'wagmi'
import { providers } from 'ethers'
import { type HttpTransport } from 'viem'
export function publicClientToProvider(publicClient: PublicClient) {
const { chain, transport } = publicClient
const network = {
chainId: chain.id,
name: chain.name,
ensAddress: chain.contracts?.ensRegistry?.address,
}
if (transport.type === 'fallback')
return new providers.FallbackProvider(
(transport.transports as ReturnType<HttpTransport>[]).map(
({ value }) => new providers.JsonRpcProvider(value?.url, network),
),
)
return new providers.JsonRpcProvider(transport.url, network)
}
/** Hook to convert a viem Public Client to an ethers.js Provider. */
export function useEthersProvider({ chainId }: { chainId?: number } = {}) {
const publicClient = usePublicClient({ chainId })
return React.useMemo(() => publicClientToProvider(publicClient), [publicClient])
}
4.2如果你需要获取ethers.js V5
的signer
即
import * as React from 'react'
import { type WalletClient, useWalletClient } from 'wagmi'
import { providers } from 'ethers'
export function walletClientToSigner(walletClient: WalletClient) {
const { account, chain, transport } = walletClient
const network = {
chainId: chain.id,
name: chain.name,
ensAddress: chain.contracts?.ensRegistry?.address,
}
const provider = new providers.Web3Provider(transport, network)
const signer = provider.getSigner(account.address)
return signer
}
/** Hook to convert a viem Wallet Client to an ethers.js Signer. */
export function useEthersSigner({ chainId }: { chainId?: number } = {}) {
const { data: walletClient } = useWalletClient({ chainId })
return React.useMemo(
() => (walletClient ? walletClientToSigner(walletClient) : undefined),
[walletClient],
)
}
如果你需要获取ethers.js V5
的Web3Provider
即
yasol在项目中需要使用的Web3Provider
所以在官网的例子中做了一个修改,我们认真看获取signer
的例子,其实里面是用到了Web3Provider的,所以我们就直接return provider
记得
import * as React from 'react'
import { type WalletClient, useWalletClient } from 'wagmi'
import { providers } from 'ethers'
export function walletClientToSigner(walletClient: WalletClient) {
const { account, chain, transport } = walletClient
const network = {
chainId: chain.id,
name: chain.name,
ensAddress: chain.contracts?.ensRegistry?.address,
}
const provider = new providers.Web3Provider(transport as any, network)
return provider
}
/** Hook to convert a viem Wallet Client to an ethers.js Signer. */
export function useEthersProvider({ chainId }: { chainId?: number } = {}) {
const { data: walletClient } = useWalletClient({ chainId })
return React.useMemo(
() => (walletClient ? walletClientToSigner(walletClient) : undefined),
[walletClient],
)
}
五、发送交易的方法变动
这里主要以函数形式的调用来讲,Hook
原理相同
//旧版
const config = await prepareWriteContract({
address:`contractAddress`,
abi: `contract abi`,
functionName: `functionName`,
args: `args`,
});
const {hash, wait} = await writeContract(config);
await wait();
//新版
import { prepareWriteContract, writeContract, waitForTransaction } from '@wagmi/core';
const config = await prepareWriteContract({
address:`contractAddress`,
abi: `contract abi`,
functionName: `functionName`,
args: `args`,
});
const { hash } = await writeContract(config);
const receipt = await waitForTransaction({ hash });
console.log("receipt", receipt);
if (receipt?.status !== "success") {
console.log(receipt);
throw new Error(errorMessage);
}
六、错误信息变动
在旧版的时候,我们只需要trycatch以下,然后再catch里面捕获错误,最后用err.message就能拿到干净的错误信息。
比如:在与钱包交互的时候,用户拒绝了本次交互,那么我们使用err.message就能很完美的捕获到错误,但是新版中的err.message不仅有错误信息还有一些data数据以及viem版本信息
// 旧版v0.11
User rejected the request.
//新版本v1.0.3
User rejected the request.
Request Arguments:
from: 0x7857AeB275cE51f7C3338D9f4D2676A329A021ec
to: 0x61011FefaC5A24f30C5811801A691698A65c7A28
data: 0x2846c41500000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000260000000000000007857aeb275ce51f7c3338d9f4d2676a329a021ec0000000012000000000000000000000000000000000000000000000000000000000000000b3132333132333132333132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b3132333132333132333132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005d68747470733a2f2f6170692e6c696b6e2e636f2f6e66742f6e66742f3735353430323137343639383137343130363939373037333031393539353436333134303136333637303432353032363632353432323735333831302f7b69647d000000000000000000000000000000000000000000000000000000000000000000005f68747470733a2f2f6170692e6c696b6e2e636f2f6e66742f636f6c6c656374696f6e2f37353534303231373436393831373431303639393730373330313935393534363331343031363336373034323530323636323534323237353338313000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000021b0b84ffab5a8c48291f5ec9d9fdb9aef574052
Details: MetaMask Tx Signature: User denied transaction signature.
Version: viem@1.1.7
解决办法:
在拿到err.message后用split(".")去截取到User rejected the request
类似的错误信息
import {sendMessage} from "./message";
const errorMessage = (err: any) => {
console.log(err.message);
const metamaskError = err?.message?.split(".")[0] || "Unknown error";
const message = err?.message ? metamaskError : err;
sendMessage("error", message);
};
export default errorMessage;
总结
Rainbowkit
和 Wagmi
的本次更新相对来说是变动比较大的,在更新日志中有一大堆更新,但是以上内容只是针对项目目前需要而写的一部分,大家也可以前往Wagmi
的更新日志中查看全部更新,做了很多优化,有机会的话,也去看看viem
的用法。以上的解决方案仅为自己的想法和思路,如果有更好的方法,欢迎大家相互讨论学习。
Wagmi更新日志
:wagmi.sh/core/migrat…
转载自:https://juejin.cn/post/7248890696819933245