particle-web-demo
particle-web-demo copied to clipboard
Update wagmi starter with Wagmi v2
The current example uses v1 and it's not compatible with Wagmi v2. Quickly looking at the migration guides on Wagmi website didn't help much to be honest.
Thanks!
For anyone looking for a compatible one, here is my attempt.
It seems to be working. Unsure tho, how getWalletClient is even used TBH and whether it was used in the original version TBH. So I still need a bit of clarification/help with that if it's important.
import { createWalletClient, custom, getAddress, UserRejectedRequestError } from 'viem'
import {
type AuthType,
type Config,
type LoginOptions,
type ParticleNetwork,
} from '@particle-network/auth'
import type { ParticleProvider } from '@particle-network/provider'
import { createConnector } from '@wagmi/core'
export type ParticleOptions = Config
const ID_NAME_MAPPING = {
apple: 'Apple',
google: 'Google',
phone: 'Phone',
facebook: 'Facebook',
discord: 'Discord',
github: 'GitHub',
twitch: 'Twitch',
twitter: 'Twitter',
microsoft: 'Microsoft',
linkedin: 'LinkedIn',
jwt: 'Jwt',
} satisfies Record<Exclude<AuthType, 'email'>, string>
export function particle({
id,
options,
loginOptions = {},
}: {
readonly id?: AuthType
readonly name?: string
options: ParticleOptions
loginOptions?: Omit<LoginOptions, 'preferredAuthType'>
}) {
return createConnector<
ParticleProvider,
{
client: ParticleNetwork | null
provider: ParticleProvider | null
}
>((config) => {
const name = id ? ID_NAME_MAPPING[id as Exclude<AuthType, 'email'>] : 'Particle'
if (id) {
;(loginOptions as LoginOptions).preferredAuthType = id
}
return {
id: id ?? 'particle',
name: name,
client: null,
provider: null,
type: 'Particle',
async connect({ chainId }: { chainId?: number } = {}) {
try {
const provider = await this.getProvider()
provider.on('accountsChanged', this.onAccountsChanged)
provider.on('chainChanged', this.onChainChanged)
provider.on('disconnect', this.onDisconnect)
config.emitter.emit('message', { type: 'connecting' })
// Switch to chain if provided
let id = await this.getChainId()
if (chainId && id !== chainId) {
const chain = await this.switchChain!({ chainId })
id = chain.id
}
if (!this.client?.auth.isLogin()) {
await this.client?.auth.login(loginOptions)
}
const accounts = await this.getAccounts()
return {
accounts,
chainId: id,
}
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((error as any).code === 4011) {
throw new UserRejectedRequestError(error as Error)
}
throw error
}
},
async disconnect() {
const provider = await this.getProvider()
provider.removeListener('accountsChanged', this.onAccountsChanged)
provider.removeListener('chainChanged', this.onChainChanged)
provider.removeListener('disconnect', this.onDisconnect)
await provider.disconnect()
},
async getAccounts() {
const provider = await this.getProvider()
const accounts = await provider.request({
method: 'eth_accounts',
})
// return checksum address
return [getAddress(accounts[0] as string)]
},
async getChainId() {
const provider = await this.getProvider()
const chainId = await provider.request({ method: 'eth_chainId' })
return Number(chainId)
},
async getProvider() {
if (!this.provider) {
const [{ ParticleNetwork }, { ParticleProvider }] = await Promise.all([
import('@particle-network/auth'),
import('@particle-network/provider'),
])
this.client = new ParticleNetwork(options)
this.provider = new ParticleProvider(this.client.auth)
}
return this.provider
},
async getWalletClient({ chainId }: { chainId?: number } = {}) {
const [provider, account] = await Promise.all([
this.getProvider(),
this.getAccounts(),
])
const chain = config.chains.find((x) => x.id === chainId)!
if (!provider) {
throw new Error('provider is required.')
}
return createWalletClient({
account: account[0],
chain,
transport: custom(provider),
})
},
async isAuthorized() {
try {
await this.getProvider()
return this.client!.auth.isLogin() && this.client!.auth.walletExist()
} catch {
return false
}
},
async switchChain({ chainId }) {
const provider = await this.getProvider()
const id = `0x${chainId.toString(16)}`
await provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: id }],
})
return (
config.chains.find((x) => x.id === chainId) ?? {
id: chainId,
name: `Chain ${id}`,
network: `${id}`,
nativeCurrency: { name: 'Ether', decimals: 18, symbol: 'ETH' },
rpcUrls: { default: { http: [''] }, public: { http: [''] } },
}
)
},
onAccountsChanged(accounts) {
if (accounts.length === 0) {
config.emitter.emit('disconnect')
} else {
config.emitter.emit('change', {
accounts: accounts.map((it) => getAddress(it)),
})
}
},
onChainChanged(chainId) {
const id = Number(chainId)
config.emitter.emit('change', { chainId: id })
},
async onDisconnect() {
config.emitter.emit('disconnect')
},
}
})
}