Skip to content

Commit

Permalink
Merge pull request #484 from alephium/support-custom-connectors
Browse files Browse the repository at this point in the history
Support custom connectors in web3-react
  • Loading branch information
polarker authored Dec 25, 2024
2 parents c77c3f3 + 142d5d9 commit 045a73e
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 154 deletions.
16 changes: 6 additions & 10 deletions packages/walletconnect/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ import {
ProviderEvent,
ProviderEventArgument,
RelayMethod,
ProjectMetaData,
SignClientOptions,
ChainInfo
} from './types'
import { isMobile } from './utils'
Expand All @@ -80,18 +80,14 @@ import { Sema } from 'async-sema'

const REQUESTS_PER_SECOND_LIMIT = 5

export interface ProviderOptions extends EnableOptionsBase {
export interface ProviderOptions extends EnableOptionsBase, SignClientOptions {
// Alephium options
networkId: NetworkId // the id of the network, e.g. mainnet, testnet or devnet.
addressGroup?: number // either a specific group or undefined to support all groups
methods?: RelayMethod[] // all of the methods to be used in relay; no need to configure in most cases

// WalletConnect options
projectId?: string
metadata?: ProjectMetaData // metadata used to initialize a sign client
logger?: string // default logger level is Error; no need to configure in most cases
client?: SignClient // existing sign client; no need to configure in most cases
relayUrl?: string // the url of the relay server; no need to configure in most cases
}

export class WalletConnectProvider extends SignerProvider {
Expand Down Expand Up @@ -240,7 +236,8 @@ export class WalletConnectProvider extends SignerProvider {
// ---------- Private ----------------------------------------------- //

private getWCStorageKey(prefix: string, version: string, name: string): string {
return prefix + version + '//' + name
const customStoragePrefix = this.providerOpts.customStoragePrefix ? `:${this.providerOpts.customStoragePrefix}` : ''
return prefix + version + customStoragePrefix + '//' + name
}

private async getSessionTopics(storage: KeyValueStorage): Promise<string[]> {
Expand Down Expand Up @@ -334,10 +331,9 @@ export class WalletConnectProvider extends SignerProvider {
this.client =
this.providerOpts.client ||
(await SignClient.init({
...this.providerOpts,
logger: this.providerOpts.logger || LOGGER,
relayUrl: this.providerOpts.relayUrl || RELAY_URL,
projectId: this.providerOpts.projectId,
metadata: this.providerOpts.metadata // fetch metadata automatically if not provided?
relayUrl: this.providerOpts.relayUrl || RELAY_URL
}))
}

Expand Down
1 change: 1 addition & 0 deletions packages/walletconnect/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,4 @@ export interface ChainInfo {
}

export type ProjectMetaData = SignClientTypes.Metadata
export type SignClientOptions = SignClientTypes.Options
25 changes: 18 additions & 7 deletions packages/web3-react/src/components/AlephiumConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
useConnectSettingContext
} from '../contexts/alephiumConnect'
import { getLastConnectedAccount, removeLastConnectedAccount } from '../utils/storage'
import { ConnectResult, getConnectorById } from '../utils/connector'
import { Connectors, ConnectResult, createDefaultConnectors } from '../utils/connector'
import { useInjectedProviders } from '../hooks/useInjectedProviders'

export const ConnectSettingProvider: React.FC<{
Expand Down Expand Up @@ -121,8 +121,9 @@ export const AlephiumConnectProvider: React.FC<{
network: NetworkId
addressGroup?: number
keyType?: KeyType
connectors?: Partial<Connectors>
children?: React.ReactNode
}> = ({ network, addressGroup, keyType, children }) => {
}> = ({ network, addressGroup, keyType, children, connectors }) => {
// Only allow for mounting AlephiumConnectProvider once, so we avoid weird global
// state collisions.
const context = useContext(AlephiumConnectContext)
Expand All @@ -134,6 +135,14 @@ export const AlephiumConnectProvider: React.FC<{
const [_addressGroup, setAddressGroup] = useState<number | undefined>(addressGroup)
const [_keyType, setKeyType] = useState<KeyType>(keyType ?? 'default')
const allInjectedProviders = useInjectedProviders()
const defaultConnectors = useMemo(() => createDefaultConnectors(allInjectedProviders), [allInjectedProviders])
const allConnectors: Connectors = useMemo(() => {
if (connectors === undefined || Object.keys(connectors).length === 0) {
return defaultConnectors
} else {
return { ...defaultConnectors, ...connectors }
}
}, [defaultConnectors, connectors])

useEffect(() => setNetwork(network), [network])
useEffect(() => setAddressGroup(addressGroup), [addressGroup])
Expand Down Expand Up @@ -196,15 +205,14 @@ export const AlephiumConnectProvider: React.FC<{
: [lastConnectorId].concat(allConnectorIds.filter((c) => c !== lastConnectorId))

for (const connectorId of sortedConnectorIds) {
const connector = getConnectorById(connectorId)
const connector = allConnectors[`${connectorId}`]
if (connector.autoConnect !== undefined) {
const result = await connector.autoConnect({
network,
addressGroup,
keyType,
onDisconnected,
onConnected,
allInjectedProviders: connectorId === 'injected' ? allInjectedProviders : undefined
onConnected
})
if (result !== undefined) {
return
Expand Down Expand Up @@ -234,7 +242,8 @@ export const AlephiumConnectProvider: React.FC<{
setConnectionStatus,
setAccount: updateAccount,
signerProvider,
setSignerProvider: updateSignerProvider
setSignerProvider: updateSignerProvider,
connectors: allConnectors
}

return <AlephiumConnectContext.Provider value={value}>{children}</AlephiumConnectContext.Provider>
Expand Down Expand Up @@ -313,6 +322,7 @@ type AlephiumWalletProviderProps = {
network: NetworkId
addressGroup?: number
keyType?: KeyType
connectors?: Partial<Connectors>
csrModeOnly?: boolean // whether to show the connect button only in CSR mode
children?: React.ReactNode
}
Expand All @@ -323,11 +333,12 @@ export const AlephiumWalletProvider = ({
network,
addressGroup,
keyType,
connectors,
csrModeOnly,
children
}: AlephiumWalletProviderProps) => {
return (
<AlephiumConnectProvider network={network} addressGroup={addressGroup} keyType={keyType}>
<AlephiumConnectProvider network={network} addressGroup={addressGroup} keyType={keyType} connectors={connectors}>
<ConnectSettingProvider
theme={theme === 'simple-light' || theme === 'simple-dark' ? 'auto' : theme}
mode={theme === 'simple-light' ? 'light' : theme === 'simple-dark' ? 'dark' : 'auto'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import { useConnect } from '../../../hooks/useConnect'
import { AlephiumWindowObject } from '@alephium/get-extension-wallet'
import { ConnectorButton, ConnectorIcon, ConnectorLabel, ConnectorsContainer } from '../../Pages/Connectors/styles'
import { useInjectedProviders } from '../../../hooks/useInjectedProviders'
import { getInjectedProviderId } from '../../../utils/injectedProviders'
import { InjectedProviderId } from '../../../types'

const states = {
CONNECTED: 'connected',
Expand Down Expand Up @@ -93,8 +95,8 @@ const ConnectWithInjector: React.FC<{
}> = ({ connectorId, switchConnectMethod, forceState }) => {
const { setOpen } = useConnectSettingContext()
const providers = useInjectedProviders()
const [injectedProvider, setInjectedProvider] = useState<AlephiumWindowObject | undefined>(
providers.length !== 0 ? providers[0] : undefined
const [injectedProviderId, setInjectedProviderId] = useState<InjectedProviderId | undefined>(
providers.length !== 0 ? getInjectedProviderId(providers[0]) : undefined
)
console.log(`providers size: ${providers.length}`)
const { connect } = useConnect()
Expand Down Expand Up @@ -127,23 +129,23 @@ const ConnectWithInjector: React.FC<{
)

const handleConnect = useCallback(
(injectedProvider) => {
setInjectedProvider(injectedProvider)
(injectedProviderId) => {
setInjectedProviderId(injectedProviderId)
setStatus(states.CONNECTING)
},
[setStatus, setInjectedProvider]
[setStatus, setInjectedProviderId]
)

const runConnect = useCallback(() => {
if (!hasExtensionInstalled || status === states.LISTING) return

connect(injectedProvider).then((address) => {
connect(injectedProviderId).then((address) => {
if (!!address) {
setStatus(states.CONNECTED)
}
setOpen(false)
})
}, [hasExtensionInstalled, setOpen, connect, status, injectedProvider])
}, [hasExtensionInstalled, setOpen, connect, status, injectedProviderId])

const connectTimeoutRef = useRef<ReturnType<typeof setTimeout>>()
useEffect(() => {
Expand Down Expand Up @@ -210,13 +212,13 @@ const ConnectWithInjector: React.FC<{
<>
<ConnectorsContainer>
{providers.map((provider) => {
const name = getProviderName(provider)
const id = getInjectedProviderId(provider)
return (
<ConnectorButton key={name} onClick={() => handleConnect(provider)}>
<ConnectorButton key={id} onClick={() => handleConnect(id)}>
<ConnectorIcon>
<img src={provider.icon} alt="Icon" />
</ConnectorIcon>
<ConnectorLabel>{name}</ConnectorLabel>
<ConnectorLabel>{id}</ConnectorLabel>
</ConnectorButton>
)
})}
Expand Down Expand Up @@ -497,10 +499,3 @@ const ConnectWithInjector: React.FC<{
}

export default ConnectWithInjector

function getProviderName(provider: AlephiumWindowObject): string {
if (provider.icon.includes('onekey')) {
return 'OneKey'
}
return 'Alephium'
}
2 changes: 2 additions & 0 deletions packages/web3-react/src/contexts/alephiumConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import React, { createContext, useContext } from 'react'
import { Account, KeyType, SignerProvider, NetworkId } from '@alephium/web3'
import { Theme, Mode, CustomTheme, ConnectorId } from '../types'
import { node } from '@alephium/web3'
import { Connectors } from '../utils/connector'

type Error = string | React.ReactNode | null

Expand Down Expand Up @@ -64,6 +65,7 @@ export type AlephiumConnectContextValue = {
setConnectionStatus: (status: ConnectionStatus) => void
signerProvider?: SignerProvider
setSignerProvider: (signerProvider: SignerProvider | undefined) => void
connectors: Connectors
}

export const AlephiumConnectContext = createContext<AlephiumConnectContextValue | null>(null)
Expand Down
23 changes: 16 additions & 7 deletions packages/web3-react/src/hooks/useConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,21 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
import { useAlephiumConnectContext, useConnectSettingContext } from '../contexts/alephiumConnect'
import { useCallback, useMemo } from 'react'
import { removeLastConnectedAccount } from '../utils/storage'
import { ConnectResult, getConnectorById } from '../utils/connector'
import { ConnectResult } from '../utils/connector'
import { InjectedProviderId } from '../types'

export function useConnect() {
const { connectorId } = useConnectSettingContext()
const { signerProvider, setSignerProvider, setConnectionStatus, setAccount, addressGroup, network, keyType } =
useAlephiumConnectContext()
const {
signerProvider,
setSignerProvider,
setConnectionStatus,
setAccount,
addressGroup,
network,
keyType,
connectors
} = useAlephiumConnectContext()

const onDisconnected = useCallback(() => {
removeLastConnectedAccount()
Expand All @@ -50,13 +59,13 @@ export function useConnect() {
}, [onDisconnected, onConnected, network, addressGroup, keyType])

const connector = useMemo(() => {
return getConnectorById(connectorId)
}, [connectorId])
return connectors[`${connectorId}`]
}, [connectorId, connectors])

const connect = useMemo(() => {
return async (injectedProvider?) => {
return async (injectedProviderId?: InjectedProviderId) => {
setConnectionStatus('connecting')
return await connector.connect({ ...connectOptions, injectedProvider })
return await connector.connect({ ...connectOptions, injectedProviderId })
}
}, [connector, connectOptions, setConnectionStatus])

Expand Down
2 changes: 1 addition & 1 deletion packages/web3-react/src/hooks/useInjectedProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
*/

import { useSyncExternalStore } from 'use-sync-external-store/shim'
import { injectedProviderStore } from '../utils/providers'
import { injectedProviderStore } from '../utils/injectedProviders'

export const useInjectedProviders = () =>
useSyncExternalStore(
Expand Down
1 change: 1 addition & 0 deletions packages/web3-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ export { useBalance } from './hooks/useBalance'
export { useWallet, Wallet, useWalletConfig, WalletConfig } from './hooks/useWallet'

export * from './contexts/alephiumConnect'
export * from './utils/connector'
1 change: 1 addition & 0 deletions packages/web3-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type Mode = 'light' | 'dark' | 'auto'
export type CustomTheme = any // TODO: define type
export const connectorIds = ['injected', 'walletConnect', 'desktopWallet'] as const
export type ConnectorId = (typeof connectorIds)[number]
export type InjectedProviderId = 'Alephium' | 'OneKey'

export type CustomStyle = {
theme?: Theme
Expand Down
Loading

0 comments on commit 045a73e

Please sign in to comment.