Created
May 18, 2024 05:42
-
-
Save TABASCOatw/f74c0127e0965a6dd705b2c6a49c03e6 to your computer and use it in GitHub Desktop.
Rough draft - AA-enabled Wagmi connector, hard-coded values + debugging
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { type ConnectParam, type EIP1193Provider } from '@particle-network/auth-core'; | |
import { ChainNotConfiguredError, createConnector, normalizeChainId } from '@wagmi/core'; | |
import { SmartAccount, AAWrapProvider, SendTransactionMode } from '@particle-network/aa'; | |
import { SwitchChainError, UserRejectedRequestError, getAddress, numberToHex, type ProviderRpcError } from 'viem'; | |
import { ethers } from 'ethers'; | |
particleWagmiWallet.type = 'particleWallet' as const; | |
export function particleWagmiWallet(param?: ConnectParam) { | |
type Provider = EIP1193Provider; | |
type Properties = any; | |
return createConnector<Provider, Properties>((config) => ({ | |
id: 'particleWalletSDK', | |
name: 'Particle Wallet', | |
type: particleWagmiWallet.type, | |
async connect({ chainId }: { chainId: number }) { | |
try { | |
console.log('Connecting to Particle Wallet...'); | |
const provider = await this.getProvider(); | |
if (!provider) { | |
console.error('Provider is undefined'); | |
throw new Error('Provider is undefined'); | |
} | |
console.log('Provider retrieved:', provider); | |
const smartAccount = new SmartAccount(provider, { | |
projectId: '3e63e8c0-1df6-4efb-a96e-96836accebdc', | |
clientKey: 'cx5kWWPJ0AmG80U6ePLJ3U3EpEknGBYeVlWdF4xv', | |
appId: 'c98e6688-ffea-4a66-8282-f3c7b52c012a', | |
aaOptions: { | |
accountContracts: { | |
SIMPLE: [{ chainIds: [1], version: '1.0.0' }], | |
} | |
} | |
}); | |
console.log('Smart account created:', smartAccount); | |
const customProvider = new ethers.providers.Web3Provider(new AAWrapProvider(smartAccount, SendTransactionMode.Gasless), "any"); | |
const newProvider = customProvider.getSigner(); | |
this.provider = newProvider; | |
console.log('Provider replaced:', newProvider); | |
const smartAccountAddress = await smartAccount.getAddress(); | |
console.log('Smart account address:', smartAccountAddress); | |
const accounts = [getAddress(smartAccountAddress)]; | |
newProvider.provider.on('accountsChanged', this.onAccountsChanged); | |
newProvider.provider.on('chainChanged', this.onChainChanged); | |
newProvider.provider.on('disconnect', this.onDisconnect.bind(this)); | |
let currentChainId = await this.getChainId(); | |
if (chainId && currentChainId !== chainId) { | |
const chain = await this.switchChain!({ chainId }).catch((error: any) => { | |
if (error.code === UserRejectedRequestError.code) throw error; | |
return { id: currentChainId }; | |
}); | |
currentChainId = chain?.id ?? currentChainId; | |
} | |
console.log('Connection successful:', { accounts, chainId: currentChainId }); | |
return { accounts, chainId: currentChainId }; | |
} catch (error: any) { | |
console.error('Error connecting to Particle Wallet:', error); | |
if (error.code == 4011) throw new UserRejectedRequestError(error as Error); | |
throw error; | |
} | |
}, | |
async disconnect() { | |
const provider = await this.getProvider(); | |
if (!provider) { | |
console.error('Provider is undefined'); | |
throw new Error('Provider is undefined'); | |
} | |
provider.removeListener('accountsChanged', this.onAccountsChanged); | |
provider.removeListener('chainChanged', this.onChainChanged); | |
provider.removeListener('disconnect', this.onDisconnect.bind(this)); | |
await (provider as any)?.disconnect?.(); | |
}, | |
async getAccounts() { | |
const provider = await this.getProvider(); | |
if (!provider) { | |
console.error('Provider is undefined'); | |
throw new Error('Provider is undefined'); | |
} | |
const smartAccount = new SmartAccount(provider, { | |
projectId: '3e63e8c0-1df6-4efb-a96e-96836accebdc', | |
clientKey: 'cx5kWWPJ0AmG80U6ePLJ3U3EpEknGBYeVlWdF4xv', | |
appId: 'c98e6688-ffea-4a66-8282-f3c7b52c012a', | |
aaOptions: { | |
accountContracts: { | |
SIMPLE: [{ chainIds: [1], version: '1.0.0' }], | |
} | |
} | |
}); | |
const smartAccountAddress = await smartAccount.getAddress(); | |
console.log('Fetched smart account address:', smartAccountAddress); | |
return [getAddress(smartAccountAddress)]; | |
}, | |
async getChainId() { | |
const provider = await this.getProvider(); | |
if (!provider) { | |
console.error('Provider is undefined'); | |
throw new Error('Provider is undefined'); | |
} | |
const chainId = await provider.request({ method: 'eth_chainId' }); | |
return normalizeChainId(chainId); | |
}, | |
async getProvider() { | |
if (typeof window === 'undefined') { | |
return; | |
} | |
while (!(window as any).particle?.ethereum) { | |
await new Promise((resolve) => setTimeout(() => resolve(true), 100)); | |
} | |
return (window as any).particle?.ethereum; | |
}, | |
async isAuthorized() { | |
try { | |
const provider = await this.getProvider(); | |
if (!provider) { | |
console.error('Provider is undefined'); | |
throw new Error('Provider is undefined'); | |
} | |
return (provider as any).isConnected(); | |
} catch { | |
return false; | |
} | |
}, | |
async switchChain({ chainId }: { chainId: number }) { | |
const chain = config.chains.find((chain) => chain.id === chainId); | |
if (!chain) throw new SwitchChainError(new ChainNotConfiguredError()); | |
const provider = await this.getProvider(); | |
if (!provider) { | |
console.error('Provider is undefined'); | |
throw new Error('Provider is undefined'); | |
} | |
const chainId_ = numberToHex(chain.id); | |
console.log(chain.id); | |
try { | |
await provider.request({ | |
method: 'wallet_switchEthereumChain', | |
params: [{ chainId: chainId_ }], | |
}); | |
return chain; | |
} catch (error) { | |
if ((error as ProviderRpcError).code === 4902) { | |
try { | |
await provider.request({ | |
method: 'wallet_addEthereumChain', | |
params: [ | |
{ | |
chainId: chainId_, | |
chainName: chain.name, | |
nativeCurrency: chain.nativeCurrency, | |
rpcUrls: [chain.rpcUrls.default?.http[0] ?? ''], | |
blockExplorerUrls: [chain.blockExplorers?.default.url], | |
}, | |
], | |
}); | |
return chain; | |
} catch (error) { | |
throw new UserRejectedRequestError(error as Error); | |
} | |
} | |
throw new SwitchChainError(error as Error); | |
} | |
}, | |
onAccountsChanged(accounts: string[]) { | |
if (accounts.length === 0) config.emitter.emit('disconnect'); | |
else | |
config.emitter.emit('change', { | |
accounts: accounts.map((x) => getAddress(x)), | |
}); | |
}, | |
onChainChanged(chain: string) { | |
const chainId = normalizeChainId(chain); | |
config.emitter.emit('change', { chainId }); | |
}, | |
async onDisconnect(_error: any) { | |
config.emitter.emit('disconnect'); | |
const provider = await this.getProvider(); | |
if (!provider) { | |
console.error('Provider is undefined'); | |
throw new Error('Provider is undefined'); | |
} | |
provider.removeListener('accountsChanged', this.onAccountsChanged); | |
provider.removeListener('chainChanged', this.onChainChanged); | |
provider.removeListener('disconnect', this.onDisconnect.bind(this)); | |
}, | |
})); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment