voluptatesiusto
Version:
Web3-Onboard makes it simple to connect Ethereum hardware and software wallets to your dapp. Features standardised spec compliant web3 providers for all supported wallets, framework agnostic modern javascript UI with code splitting, CSS customization, mul
204 lines (171 loc) • 5.93 kB
text/typescript
import uniqBy from 'lodash.uniqby'
import { createEIP1193Provider, type WalletInit } from '@web3-onboard/common'
import { ProviderLabel } from './types.js'
import standardWallets from './wallets.js'
import {
validateEIP6963ProviderDetail,
validateWalletOptions
} from './validation.js'
import {
containsExecutableJavaScript,
defaultWalletUnavailableMsg,
isWalletAvailable
} from './helpers.js'
import type {
InjectedWalletOptions,
CustomWindow,
InjectedWalletModule,
EIP6963AnnounceProviderEvent,
InjectedProvider
} from './types.js'
declare const window: CustomWindow
export { ProviderIdentityFlag, ProviderLabel } from './types.js'
const providers6963: InjectedWalletModule[] = []
function checkFor6963Providers() {
// Add event listener for 'eip6963:announceProvider' event
window.addEventListener('eip6963:announceProvider', (event: Event) => {
const eipEvent = event as EIP6963AnnounceProviderEvent
const { detail } = eipEvent
if (!detail) return
if (eipEvent) {
const result = validateEIP6963ProviderDetail(detail)
if (result && result.error) throw result.error
}
const { info, provider } = detail
const { name, icon } = info
if (containsExecutableJavaScript(icon)) {
console.error(
`The icon for injected wallet: ${name} contains executable JavaScript and has been blocked.`
)
return
}
// Push the provider information to the providers6963 array
providers6963.push({
label: name,
getIcon: async () => icon,
getInterface: async () => ({
provider: createEIP1193Provider(provider)
}),
platforms: ['all'],
eip6963Provider: createEIP1193Provider(provider) as InjectedProvider,
checkProviderIdentity: ({ provider }) => !!provider
})
})
// Dispatch a custom event to request the provider information
window.dispatchEvent(new CustomEvent('eip6963:requestProvider'))
}
function injected(options?: InjectedWalletOptions): WalletInit {
if (typeof window === 'undefined') return () => null
if (options) {
const result = validateWalletOptions(options)
if (result && result.error) throw result.error
}
!options?.disable6963Support && checkFor6963Providers()
return helpers => {
const { device } = helpers
const {
custom = [],
filter = {},
displayUnavailable,
sort,
walletUnavailableMessage
} = options || {}
// combine custom with standard wallets and dedupe
const allWallets = uniqBy(
[...custom, ...standardWallets, ...providers6963],
({ label }) => label
)
const wallets = allWallets.reduce(
(acc: InjectedWalletModule[], wallet: InjectedWalletModule) => {
const {
label,
platforms,
injectedNamespace,
checkProviderIdentity,
eip6963Provider
} = wallet
const walletFilters = filter[label]
const filteredWallet = walletFilters === false
const provider =
eip6963Provider ||
(window[injectedNamespace!] as CustomWindow['ethereum'])
const walletAvailable = isWalletAvailable(
provider,
checkProviderIdentity,
device
)
let excludedDevice: boolean = false
// dev specified platform filters
if (
Array.isArray(walletFilters) &&
(walletFilters.includes(device.type) ||
walletFilters.includes(device.os.name))
) {
excludedDevice = true
}
// unavailable filter
if (walletFilters === 'unavailable' && !walletAvailable) {
excludedDevice = true
}
// wallet specified platform filters
const invalidPlatform =
!platforms.includes('all') &&
!platforms.includes(device.type) &&
!platforms.includes(device.os.name)
const supportedWallet =
!filteredWallet &&
!excludedDevice &&
!invalidPlatform &&
(walletAvailable ||
displayUnavailable === true ||
(Array.isArray(displayUnavailable) &&
displayUnavailable.length &&
displayUnavailable.includes(wallet.label)))
if (supportedWallet) {
acc.push(
// modify wallet to display error if unavailable but displayUnavailable is set
(displayUnavailable === true ||
(Array.isArray(displayUnavailable) &&
displayUnavailable.length &&
displayUnavailable.includes(wallet.label))) &&
!walletAvailable
? {
...wallet,
getInterface: async () => {
throw new Error(
walletUnavailableMessage
? walletUnavailableMessage(wallet)
: defaultWalletUnavailableMsg(wallet)
)
}
}
: // otherwise add wallet to list as is
wallet
)
}
return acc
},
[] as InjectedWalletModule[]
)
if (wallets.length) {
const moreThanOneWallet = wallets.length > 1
// if more than one wallet, then remove detected wallet
const formattedWallets = wallets
.filter((wallet: InjectedWalletModule) => {
const { label } = wallet
return !(label === ProviderLabel.Detected && moreThanOneWallet)
})
// then map to the WalletModule interface
.map(({ label, getIcon, getInterface }: InjectedWalletModule) => ({
label,
getIcon,
getInterface
}))
// default sort by alphabetical
.sort((a, b) => (a.label < b.label ? -1 : a.label > b.label ? 1 : 0))
return sort ? sort(formattedWallets) : formattedWallets
}
return []
}
}
export default injected