-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: Setting `reloadOnDisconnect` = false in default for coinbaseWallet * docs: Add changeset log * feat: Add `closeModalAfterSwitchingNetwork` * feat: Add particle wallet * feat: Add particle wallet
- Loading branch information
Showing
13 changed files
with
505 additions
and
15 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@totejs/walletkit': patch | ||
--- | ||
|
||
Add particle wallet |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,4 +25,5 @@ dist-ssr | |
*.sln | ||
*.sw? | ||
.npmrc | ||
.pnpm-store | ||
.pnpm-store | ||
.env |
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
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
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
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
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
203 changes: 203 additions & 0 deletions
203
packages/walletkit/src/wallets/particleWallet/connector.ts
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
import { PARTICLE_WALLET_ID } from '.'; | ||
import { ParticleProvider } from '@particle-network/provider'; | ||
import type { AuthType } from '@particle-network/auth'; | ||
import { | ||
Chain, | ||
ChainNotConfiguredError, | ||
Connector, | ||
ConnectorNotFoundError, | ||
WalletClient, | ||
} from 'wagmi'; | ||
import { | ||
ProviderRpcError, | ||
SwitchChainError, | ||
UserRejectedRequestError, | ||
createWalletClient, | ||
custom, | ||
getAddress, | ||
numberToHex, | ||
} from 'viem'; | ||
|
||
type ParticleAuth = ConstructorParameters<typeof ParticleProvider>[0]; | ||
|
||
export type ParticleConnectorOptions = { | ||
shimDisconnect?: boolean; | ||
auth?: ParticleAuth; | ||
authType?: AuthType; | ||
}; | ||
|
||
export class ParticleConnector extends Connector<ParticleProvider, ParticleConnectorOptions> { | ||
readonly id: string = PARTICLE_WALLET_ID; | ||
readonly name: string = 'Particle'; | ||
readonly ready: boolean; | ||
|
||
protected shimDisconnectKey = `${this.id}.shimDisconnect`; | ||
private provider?: ParticleProvider; | ||
|
||
constructor({ | ||
chains, | ||
options: _options, | ||
}: { | ||
chains?: Chain[]; | ||
options?: ParticleConnectorOptions; | ||
} = {}) { | ||
const options = { | ||
name: 'Particle', | ||
shimDisconnect: true, | ||
..._options, | ||
}; | ||
|
||
super({ | ||
chains, | ||
options, | ||
}); | ||
|
||
this.name = options.name ?? this.name; | ||
this.ready = true; | ||
|
||
this.onAccountsChanged = this.onAccountsChanged.bind(this); | ||
this.onChainChanged = this.onChainChanged.bind(this); | ||
this.onDisconnect = this.onDisconnect.bind(this); | ||
} | ||
|
||
async connect({ chainId }: { chainId?: number } = {}) { | ||
if (!this.options.auth) { | ||
throw new Error('Please init Particle first'); | ||
} | ||
|
||
try { | ||
const provider = await this.getProvider(); | ||
if (!provider) throw new ConnectorNotFoundError(); | ||
|
||
provider.on('accountsChanged', this.onAccountsChanged); | ||
provider.on('chainChanged', this.onChainChanged); | ||
provider.on('disconnect', this.onDisconnect); | ||
|
||
this.emit('message', { type: 'connecting' }); | ||
|
||
if (!this.options.auth.isLogin()) { | ||
await this.options.auth.login({ | ||
preferredAuthType: this.options.authType, | ||
}); | ||
} | ||
|
||
let id = await this.getChainId(); | ||
let unsupported = this.isChainUnsupported(id); | ||
if (chainId && id !== chainId) { | ||
const chain = await this.switchChain(chainId); | ||
id = chain.id; | ||
unsupported = this.isChainUnsupported(id); | ||
} | ||
|
||
const account = await this.getAccount(); | ||
return { | ||
account, | ||
chain: { id, unsupported }, | ||
}; | ||
} catch (error) { | ||
if ((error as ProviderRpcError).code === 4001) { | ||
throw new UserRejectedRequestError(error as Error); | ||
} | ||
throw error; | ||
} | ||
} | ||
|
||
async disconnect() { | ||
const provider = await this.getProvider(); | ||
await provider.disconnect(); | ||
|
||
provider.removeListener('accountsChanged', this.onAccountsChanged); | ||
provider.removeListener('chainChanged', this.onChainChanged); | ||
provider.removeListener('disconnect', this.onDisconnect); | ||
} | ||
|
||
async getAccount() { | ||
const provider = await this.getProvider(); | ||
const accounts = await provider.request({ method: 'eth_accounts' }); | ||
return getAddress(accounts[0]); | ||
} | ||
|
||
async getChainId() { | ||
const provider = await this.getProvider(); | ||
const chainId = await provider.request({ method: 'eth_chainId' }); | ||
return Number(chainId); | ||
} | ||
|
||
async getProvider() { | ||
if (!this.options.auth) { | ||
throw new Error('Please init Particle first'); | ||
} | ||
if (!this.provider) { | ||
const { ParticleProvider } = await import('@particle-network/provider'); | ||
this.provider = new ParticleProvider(this.options.auth); | ||
} | ||
return this.provider; | ||
} | ||
|
||
async getWalletClient({ chainId }: { chainId?: number } = {}) { | ||
const [provider, account] = await Promise.all([this.getProvider(), this.getAccount()]); | ||
const chain = this.chains.find((x) => x.id === chainId); | ||
|
||
if (!provider) throw new Error('provider is required.'); | ||
|
||
return createWalletClient({ | ||
account, | ||
chain, | ||
transport: custom(provider), | ||
}) as WalletClient; | ||
} | ||
|
||
async isAuthorized() { | ||
if (!this.options.auth) { | ||
throw new Error('Please init Particle first'); | ||
} | ||
return this.options.auth.isLogin() && this.options.auth.walletExist(); | ||
} | ||
|
||
async switchChain(chainId: number) { | ||
const provider = await this.getProvider(); | ||
if (!provider) throw new ConnectorNotFoundError(); | ||
const id = numberToHex(chainId); | ||
|
||
try { | ||
await provider.request({ | ||
method: 'wallet_switchEthereumChain', | ||
params: [{ chainId: id }], | ||
}); | ||
|
||
return ( | ||
this.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: [''] } }, | ||
} | ||
); | ||
} catch (error) { | ||
const chain = this.chains.find((x) => x.id === chainId); | ||
if (!chain) { | ||
throw new ChainNotConfiguredError({ chainId, connectorId: this.id }); | ||
} | ||
throw new SwitchChainError(error as Error); | ||
} | ||
} | ||
|
||
protected onAccountsChanged(accounts: string[]) { | ||
if (accounts.length === 0) { | ||
this.emit('disconnect'); | ||
} else { | ||
this.emit('change', { account: getAddress(accounts[0]) }); | ||
} | ||
} | ||
|
||
protected onChainChanged(chainId: number | string) { | ||
const id = Number(chainId); | ||
const unsupported = this.isChainUnsupported(id); | ||
this.emit('change', { chain: { id, unsupported } }); | ||
} | ||
|
||
protected onDisconnect() { | ||
this.emit('disconnect'); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { SVGIconProps } from '../..'; | ||
|
||
export const ParticleWalletTransparentIcon = (props: SVGIconProps) => { | ||
return <ParticleWalletIcon width={34} height={34} {...props} />; | ||
}; | ||
|
||
export const ParticleWalletIcon = (props: SVGIconProps) => { | ||
return ( | ||
<svg width="68" height="68" viewBox="0 0 68 68" fill="none" {...props}> | ||
<path | ||
d="M0 18.1333C0 8.11857 8.11857 0 18.1333 0H49.8667C59.8814 0 68 8.11857 68 18.1333V49.8667C68 59.8814 59.8814 68 49.8667 68H18.1333C8.11857 68 0 59.8814 0 49.8667V18.1333Z" | ||
fill="black" | ||
/> | ||
<path | ||
fillRule="evenodd" | ||
clipRule="evenodd" | ||
d="M13.2812 13.2812H27.0938V27.0938H13.2812V13.2812ZM40.9062 27.0938H27.0938V40.9062H13.2812V54.7188H27.0938V40.9062H40.9062V54.7188H54.7188V40.9062H40.9062V27.0938ZM40.9062 27.0938V13.2812H54.7188V27.0938H40.9062Z" | ||
fill="white" | ||
/> | ||
</svg> | ||
); | ||
}; |
Oops, something went wrong.