saepenatus
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
387 lines (327 loc) • 9.48 kB
text/typescript
import { SofiaProRegular } from '@web3-onboard/common'
import connectWallet from './connect.js'
import disconnectWallet from './disconnect.js'
import setChain from './chain.js'
import { state } from './store/index.js'
import { reset$, wallets$ } from './streams.js'
import initI18N from './i18n/index.js'
import App from './views/Index.svelte'
import type { InitOptions, Notify } from './types.js'
import { APP_INITIAL_STATE, STORAGE_KEYS } from './constants.js'
import { configuration, updateConfiguration } from './configuration.js'
import updateBalances from './update-balances.js'
import { chainIdToHex, getLocalStore } from './utils.js'
import { preflightNotifications } from './preflight-notifications.js'
import {
validateInitOptions,
validateNotify,
validateNotifyOptions
} from './validation.js'
import {
addChains,
updateAccountCenter,
updateNotify,
customNotification,
setLocale,
setPrimaryWallet,
setWalletModules,
updateConnectModal,
updateTheme
} from './store/actions.js'
import type { PatchedEIP1193Provider } from '@web3-onboard/transaction-preview'
import { getBlocknativeSdk } from './services.js'
const API = {
connectWallet,
disconnectWallet,
setChain,
state: {
get: state.get,
select: state.select,
actions: {
setWalletModules,
setLocale,
updateNotify,
customNotification,
preflightNotifications,
updateBalances,
updateAccountCenter,
setPrimaryWallet,
updateTheme
}
}
}
export type OnboardAPI = typeof API
export type {
InitOptions,
ConnectOptions,
DisconnectOptions,
WalletState,
ConnectedChain,
AccountCenter,
AppState,
CustomNotification,
Notification,
Notify,
UpdateNotification,
PreflightNotificationsOptions,
Theme
} from './types.js'
export type { EIP1193Provider } from '@web3-onboard/common'
function init(options: InitOptions): OnboardAPI {
if (typeof window === 'undefined') return API
if (options) {
const error = validateInitOptions(options)
if (error) {
throw error
}
}
const {
wallets,
chains,
appMetadata = null,
i18n,
accountCenter,
apiKey,
notify,
gas,
connect,
containerElements,
transactionPreview,
theme
} = options
if (containerElements) updateConfiguration({ containerElements })
const { device, svelteInstance } = configuration
if (svelteInstance) {
// if already initialized, need to cleanup old instance
console.warn('Re-initializing Onboard and resetting back to initial state')
reset$.next()
}
initI18N(i18n)
addChains(chainIdToHex(chains))
if (typeof connect !== undefined) {
updateConnectModal(connect)
}
// update accountCenter
if (typeof accountCenter !== 'undefined') {
let accountCenterUpdate
if (device.type === 'mobile') {
accountCenterUpdate = {
...APP_INITIAL_STATE.accountCenter,
...(accountCenter.mobile ? accountCenter.mobile : {})
}
} else if (accountCenter.desktop) {
accountCenterUpdate = {
...APP_INITIAL_STATE.accountCenter,
...accountCenter.desktop
}
}
updateAccountCenter(accountCenterUpdate)
}
// update notify
if (typeof notify !== 'undefined') {
if ('desktop' in notify || 'mobile' in notify) {
const error = validateNotifyOptions(notify)
if (error) {
throw error
}
if (
(!notify.desktop || (notify.desktop && !notify.desktop.position)) &&
accountCenter &&
accountCenter.desktop &&
accountCenter.desktop.position
) {
notify.desktop.position = accountCenter.desktop.position
}
if (
(!notify.mobile || (notify.mobile && !notify.mobile.position)) &&
accountCenter &&
accountCenter.mobile &&
accountCenter.mobile.position
) {
notify.mobile.position = accountCenter.mobile.position
}
let notifyUpdate: Partial<Notify>
if (device.type === 'mobile' && notify.mobile) {
notifyUpdate = {
...APP_INITIAL_STATE.notify,
...notify.mobile
}
} else if (notify.desktop) {
notifyUpdate = {
...APP_INITIAL_STATE.notify,
...notify.desktop
}
}
updateNotify(notifyUpdate)
} else {
const error = validateNotify(notify as Notify)
if (error) {
throw error
}
const notifyUpdate: Partial<Notify> = {
...APP_INITIAL_STATE.notify,
...notify
}
updateNotify(notifyUpdate)
}
} else {
const notifyUpdate: Partial<Notify> = APP_INITIAL_STATE.notify
updateNotify(notifyUpdate)
}
const app = svelteInstance || mountApp()
updateConfiguration({
appMetadata,
svelteInstance: app,
apiKey,
initialWalletInit: wallets,
gas,
transactionPreview
})
if (apiKey && transactionPreview) {
const getBnSDK = async () => {
transactionPreview.init({
containerElement: '#transaction-preview-container',
sdk: await getBlocknativeSdk(),
apiKey
})
wallets$.subscribe(wallets => {
wallets.forEach(({ provider }) => {
transactionPreview.patchProvider(provider as PatchedEIP1193Provider)
})
})
}
getBnSDK()
}
theme && updateTheme(theme)
// handle auto connection of last wallet
if (connect && connect.autoConnectLastWallet) {
const lastConnectedWallet = getLocalStore(
STORAGE_KEYS.LAST_CONNECTED_WALLET
)
lastConnectedWallet &&
API.connectWallet({
autoSelect: { label: lastConnectedWallet, disableModals: true }
})
}
return API
}
function mountApp() {
class Onboard extends HTMLElement {
constructor() {
super()
}
}
if (!customElements.get('onboard-v2')) {
customElements.define('onboard-v2', Onboard)
}
// Add Fonts to main page
const styleEl = document.createElement('style')
styleEl.innerHTML = `
${SofiaProRegular}
`
document.body.appendChild(styleEl)
// add to DOM
const onboard = document.createElement('onboard-v2')
const target = onboard.attachShadow({ mode: 'open' })
onboard.style.all = 'initial'
target.innerHTML = `
<style>
:host {
/* COLORS */
--white: white;
--black: black;
--primary-1: #2F80ED;
--primary-100: #eff1fc;
--primary-200: #d0d4f7;
--primary-300: #b1b8f2;
--primary-400: #929bed;
--primary-500: #6370e5;
--primary-600: #454ea0;
--primary-700: #323873;
--gray-100: #ebebed;
--gray-200: #c2c4c9;
--gray-300: #999ca5;
--gray-400: #707481;
--gray-500: #33394b;
--gray-600: #242835;
--gray-700: #1a1d26;
--success-100: #d1fae3;
--success-200: #baf7d5;
--success-300: #a4f4c6;
--success-400: #8df2b8;
--success-500: #5aec99;
--success-600: #18ce66;
--success-700: #129b4d;
--danger-100: #ffe5e6;
--danger-200: #ffcccc;
--danger-300: #ffb3b3;
--danger-400: #ff8080;
--danger-500: #ff4f4f;
--danger-600: #cc0000;
--danger-700: #660000;
--warning-100: #ffefcc;
--warning-200: #ffe7b3;
--warning-300: #ffd780;
--warning-400: #ffc74c;
--warning-500: #ffaf00;
--warning-600: #cc8c00;
--warning-700: #664600;
/* FONTS */
--font-family-normal: Sofia Pro;
--font-size-1: 3rem;
--font-size-2: 2.25rem;
--font-size-3: 1.5rem;
--font-size-4: 1.25rem;
--font-size-5: 1rem;
--font-size-6: .875rem;
--font-size-7: .75rem;
--font-line-height-1: 24px;
--font-line-height-2: 20px;
--font-line-height-3: 16px;
--font-line-height-4: 12px;
/* SPACING */
--spacing-1: 3rem;
--spacing-2: 2rem;
--spacing-3: 1.5rem;
--spacing-4: 1rem;
--spacing-5: 0.5rem;
--spacing-6: 0.25rem;
--spacing-7: 0.125rem;
/* BORDER RADIUS */
--border-radius-1: 24px;
--border-radius-2: 20px;
--border-radius-3: 16px;
--border-radius-4: 12px;
--border-radius-5: 8px;
/* SHADOWS */
--shadow-0: none;
--shadow-1: 0px 4px 12px rgba(0, 0, 0, 0.1);
--shadow-2: inset 0px -1px 0px rgba(0, 0, 0, 0.1);
--shadow-3: 0px 4px 16px rgba(0, 0, 0, 0.2);
/* MODAL POSITIONING */
--modal-z-index: 10;
--modal-top: unset;
--modal-right: unset;
--modal-bottom: unset;
--modal-left: unset;
/* MODAL STYLES */
--modal-backdrop: rgba(0, 0, 0, 0.6);
}
</style>
`
const connectModalContEl = configuration.containerElements.connectModal
const containerElementQuery =
connectModalContEl || state.get().accountCenter.containerElement || 'body'
const containerElement = document.querySelector(containerElementQuery)
if (!containerElement) {
throw new Error(
`Element with query ${containerElementQuery} does not exist.`
)
}
containerElement.appendChild(onboard)
const app = new App({
target
})
return app
}
export default init