diff --git a/.github/ISSUE_TEMPLATE/BUG.yml b/.github/ISSUE_TEMPLATE/BUG.yml index 405862d44..639ffb678 100644 --- a/.github/ISSUE_TEMPLATE/BUG.yml +++ b/.github/ISSUE_TEMPLATE/BUG.yml @@ -5,11 +5,15 @@ labels: [bug] assignees: - taylorjdawson - aaronbarnardsound + - Adamj1232 + - mahmud-bn body: - type: markdown attributes: value: | - Thanks for taking the time to fill out this bug report! + Thanks for taking the time to fill out this bug report! Note that the more detailed the report the faster we can get the issue fixed. + When possible, please provide a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) this will + reduce the time it takes us to fix the issue. - type: textarea attributes: label: Current Behavior @@ -25,7 +29,7 @@ body: - type: textarea attributes: label: Steps To Reproduce - description: Steps to reproduce the behavior. + description: Steps to reproduce the behavior. Link or paste your [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) here. placeholder: | 1. In this environment... 2. With this config... @@ -33,9 +37,46 @@ body: 4. See error... validations: required: false + - type: dropdown + attributes: + label: What package is effected by this issue? + options: + - @web3-onboard/core + - @web3-onboard/common + - @web3-onboard/coinbase + - @web3-onboard/decent + - @web3-onboard/formatic + - @web3-onboard/gnosis + - @web3-onboard/injected + - @web3-onboard/keepkey + - @web3-onboard/keystone + - @web3-onboard/ledger + - @web3-onboard/magic + - @web3-onboard/mew + - @web3-onboard/portis + - @web3-onboard/react + - @web3-onboard/torus + - @web3-onboard/trezor + - @web3-onboard/vue + - @web3-onboard/walletconnect + - @web3-onboard/walletlink + - @web3-onboard/web3auth + - bnc-onboard (v1) + validations: + required: true + - type: dropdown + attributes: + label: Is this a build or a runtime issue? + multiple: true + options: + - Build + - Runtime + - N/A + validations: + required: true - type: input attributes: - label: Onboard Version + label: Package Version description: What version of Onboard are you using? validations: required: true @@ -43,8 +84,6 @@ body: attributes: label: Node Version description: What version of NodeJS are you running? - validations: - required: true - type: dropdown id: browsers attributes: @@ -70,3 +109,11 @@ body: Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. validations: required: false + - type: checkboxes + id: terms + attributes: + label: Sanity Check + description: Sanity check to ensure that issue has been properly filled out to reduce friction for all involved parties. + options: + - label: If this is a build issue, I have included my build config. If this is a runtime issue, I have included reproduction steps and/or a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example). + required: true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..aaf420460 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +packages/**/dist \ No newline at end of file diff --git a/README.md b/README.md index 92fe4a95c..0b467ca0c 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,20 @@ ## Quickstart -Install the core Onboard library and the injected wallets module to support browser extension and mobile wallets: +Install the core Onboard library, the injected wallets module and optionally ethers js to support browser extension and mobile wallets: -`npm i @web3-onboard/core @web3-onboard/injected-wallets` +**NPM** +`npm i @web3-onboard/core @web3-onboard/injected-wallets ethers` -- [@web3-onboard/core Official NPM Documentation](https://www.npmjs.com/package/@web3-onboard/core) +**Yarn** +`yarn add @web3-onboard/core @web3-onboard/injected-wallets ethers` Then initialize in your app: ```javascript import Onboard from '@web3-onboard/core' import injectedModule from '@web3-onboard/injected-wallets' +import { ethers } from 'ethers' const MAINNET_RPC_URL = 'https://mainnet.infura.io/v3/' @@ -37,17 +40,31 @@ const onboard = Onboard({ label: 'Ethereum Mainnet', rpcUrl: MAINNET_RPC_URL } - ], - appMetadata: { - name: 'My App', - icon: '', - description: 'My app using Onboard' - } + ] }) const wallets = await onboard.connectWallet() console.log(wallets) + +if (wallets[0]) { + // create an ethers provider with the last connected wallet provider + const ethersProvider = new ethers.providers.Web3Provider( + wallets[0].provider, + 'any' + ) + + const signer = ethersProvider.getSigner() + + // send a transaction with the ethers provider + const txn = await signer.sendTransaction({ + to: '0x', + value: 100000000000000 + }) + + const receipt = await txn.wait() + console.log(receipt) +} ``` ## Documentation @@ -64,22 +81,23 @@ For full documentation, check out the README.md for each package: **SDK Wallets** -- [Fortmatic](packages/fortmatic/README.md) +- [Coinbase](packages/coinbase/README.md) +- [WalletConnect](packages/walletconnect/README.md) - [Gnosis](packages/gnosis/README.md) -- [MEW](packages/mew/README.md) +- [Magic](packages/magic/README.md) +- [Fortmatic](packages/fortmatic/README.md) - [Portis](packages/portis/README.md) -- [Torus](packages/torus/README.md) -- [WalletConnect](packages/walletconnect/README.md) -- [WalletLink](packages/walletlink/README.md) -- Magic (in active development) +- [MEW](packages/mew/README.md) +- [Web3Auth](packages/web3auth/README.md) **Hardware Wallets** -- [KeepKey](packages/keepkey/README.md) - [Ledger](packages/ledger/README.md) - [Trezor](packages/trezor/README.md) - [Keystone](packages/keystone/README.md) +- [KeepKey](packages/keepkey/README.md) - [D'CENT](packages/dcent/README.md) + **Frameworks** - [React](packages/react/README.md) diff --git a/package.json b/package.json index 824fad638..1ad8867b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "web3-onboard-monorepo", - "version": "2.1.0", + "version": "2.2.0", "private": true, "workspaces": [ "./packages/*" diff --git a/packages/coinbase/package.json b/packages/coinbase/package.json index 2ea4ac5a4..68c3138d1 100644 --- a/packages/coinbase/package.json +++ b/packages/coinbase/package.json @@ -1,6 +1,6 @@ { "name": "@web3-onboard/coinbase", - "version": "2.0.5", + "version": "2.0.6", "description": "Coinbase Wallet module for web3-onboard", "module": "dist/index.js", "browser": "dist/index.js", @@ -21,6 +21,6 @@ }, "dependencies": { "@coinbase/wallet-sdk": "^3.0.5", - "@web3-onboard/common": "2.1.2" + "@web3-onboard/common": "^2.1.3" } } diff --git a/packages/common/package.json b/packages/common/package.json index b0eca131e..525a1d8f0 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@web3-onboard/common", - "version": "2.1.2", + "version": "2.1.3", "scripts": { "build": "rollup -c", "dev": "rollup -c -w", diff --git a/packages/common/src/hdwallets.ts b/packages/common/src/hdwallets.ts index 7afd50b92..30656536b 100644 --- a/packages/common/src/hdwallets.ts +++ b/packages/common/src/hdwallets.ts @@ -1,6 +1,6 @@ import type Common from '@ethereumjs/common' import type { BigNumber } from 'ethers' -import type { CustomNetwork } from './types' +import type { CustomNetwork, EIP1193Provider, RPCResponse } from './types' import type { TransactionRequest } from '@ethersproject/providers' /** @@ -19,18 +19,22 @@ export const getCommon = async ({ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const CommonConstructor: typeof Common = Common.default || Common + + const commonOptions = { + // Berlin is the minimum hardfork that will allow for EIP1559 + hardfork: Hardfork.Berlin, + // List of supported EIPS + eips: [1559] + } let common: Common try { common = new CommonConstructor({ chain: customNetwork || chainId, - // Berlin is the minimum hardfork that will allow for EIP1559 - hardfork: Hardfork.Berlin, - // List of supported EIPS - eips: [1559] + ...commonOptions }) } catch (e: any) { if (e.message && /Chain.*not supported/.test(e.message)) { - common = CommonConstructor.custom({ chainId }) + common = CommonConstructor.custom({ chainId }, commonOptions) } else { throw e } @@ -77,3 +81,34 @@ export const bigNumberFieldsToStrings = ( }), transaction ) as StringifiedTransactionRequest + +/** + * Helper method for hardware wallets to build an object + * with a request method used for making rpc requests. + * @param getRpcUrl - callback used to get the current chain's rpc url + * @returns An object with a request method + * to be called when making rpc requests + */ +export const getHardwareWalletProvider = ( + getRpcUrl: () => string +): { request: EIP1193Provider['request'] } => ({ + request: ({ method, params }) => + fetch(getRpcUrl(), { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: '42', + method, + params + }) + }).then(async res => { + const response = (await res.json()) as RPCResponse + if ('error' in response) { + throw response.error + } + return response.result + }) +}) diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 693820822..4a024f5c2 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -53,7 +53,8 @@ import type { Chain, TokenSymbol, CustomNetwork, - TransactionObject + TransactionObject, + RPCResponse } from './types' export { ProviderRpcErrorCode } from './types' @@ -62,7 +63,11 @@ export { createEIP1193Provider } from './eip-1193' export { default as accountSelect } from './account-select' export { entryModal } from './entry-modal' export { SofiaProLight, SofiaProRegular, SofiaProSemiBold } from './fonts' -export { getCommon, bigNumberFieldsToStrings } from './hdwallets' +export { + getCommon, + bigNumberFieldsToStrings, + getHardwareWalletProvider +} from './hdwallets' export type { RequestPatch, @@ -119,5 +124,6 @@ export type { Chain, TokenSymbol, CustomNetwork, - TransactionObject + TransactionObject, + RPCResponse } diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index ed14165f2..c54fc3ddf 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -466,3 +466,10 @@ export interface BootstrapNode { location: string comment: string } + +export interface RPCResponse { + id: number + jsonrpc: string + error?: { code: number; message: string } + result?: any +} diff --git a/packages/core/README.md b/packages/core/README.md index 303f0822c..0e7294276 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -17,6 +17,7 @@ Note: - MEW wallet currently fails to install on M1 macs - All wallet modules (except for `injected-wallets`) require extra dependencies and may require polyfilling the node built in modules for the browser. See the [Build Environments](#build-environments) section for more info - **If using React** you may be interested in checking out the React Hooks package here - https://www.npmjs.com/package/@web3-onboard/react +- **If using Vue** you may be interested in checking out the Vue package here - https://www.npmjs.com/package/@web3-onboard/vue ## Initialization @@ -121,20 +122,22 @@ type AccountCenterPosition = **`notify`** Notify provides by default transaction notifications for all connected wallets on the current blockchain. When switching chains the previous chain listeners remain active for 60 seconds to allow capture and report of an remaining transactions that may be in flight. By default transaction notifications are captured if a DAppID is provided in the Onboard config along with the Account Center being enabled. -An object that defines whether transaction notifications will display (defaults to true if an API key is provided). This object contains an `enabled` flag prop and an optional `transactionHandler` which is a callback that can disable or allow customizations of notifications. +An object that defines whether transaction notifications will display (defaults to true if an API key is provided). This object contains an `enabled` flag prop and an optional `transactionHandler` which is a callback that can disable or allow customizations of notifications. Currently notifications are positioned in the same location as the account center (either below, if the Account Center is positioned along the top, or above if positioned on the bottom of the view). The `transactionHandler` can react off any property of the Ethereum TransactionData returned to the callback from the event (see console.log in example init). In turn, it can return a Custom `Notification` object to define the verbiage, styling, or add functionality: - - `Notification.message` - to completely customize the message shown - - `Notification.eventCode` - handle codes in your own way - see codes here under the notify prop [default en file here](src/i18n/en.json) - - `Notification.type` - icon type displayed (see `NotificationType` below for options) - - `Notification.autoDismiss` - time (in ms) after which the notification will be dismissed. If set to `0` the notification will remain on screen until the user dismisses the notification, refreshes the page or navigates away from the site with the notifications - - `Notification.link` - add link to the transaction hash. For instance, a link to the transaction on etherscan - - `Notification.onClick()` - onClick handler for when user clicks the notification element - Notify can also be styled by using the CSS variables found below. These are setup to allow maximum customization with base styling variables setting the global theme (i.e. `--onboard-grey-600`) along with more precise component level styling variables available (`--notify-onboard-grey-600`) with the latter taking precedent if defined +- `Notification.message` - to completely customize the message shown +- `Notification.eventCode` - handle codes in your own way - see codes here under the notify prop [default en file here](src/i18n/en.json) +- `Notification.type` - icon type displayed (see `NotificationType` below for options) +- `Notification.autoDismiss` - time (in ms) after which the notification will be dismissed. If set to `0` the notification will remain on screen until the user dismisses the notification, refreshes the page or navigates away from the site with the notifications +- `Notification.link` - add link to the transaction hash. For instance, a link to the transaction on etherscan +- `Notification.onClick()` - onClick handler for when user clicks the notification element - If notifications are enabled the notifications can be handled through onboard app state as seen below. - ```javascript +Notify can also be styled by using the CSS variables found below. These are setup to allow maximum customization with base styling variables setting the global theme (i.e. `--onboard-grey-600`) along with more precise component level styling variables available (`--notify-onboard-grey-600`) with the latter taking precedent if defined + +If notifications are enabled the notifications can be handled through onboard app state as seen below. + +```javascript const wallets = onboard.state.select('notifications') const { unsubscribe } = wallets.subscribe(update => console.log('transaction notifications: ', update) @@ -145,8 +148,13 @@ unsubscribe() ``` ```typescript + export type NotifyOptions = { - enabled: boolean // default: true + desktop: Notify + mobile: Notify +} +export type Notify = { + enabled: boolean // default: true /** * Callback that receives all transaction events * Return a custom notification based on the event @@ -156,8 +164,15 @@ export type NotifyOptions = { transactionHandler?: ( event: EthereumTransactionData ) => TransactionHandlerReturn + position: CommonPositions } +export type CommonPositions = +| 'topRight' +| 'bottomRight' +| 'bottomLeft' +| 'topLeft' + export type TransactionHandlerReturn = CustomNotification | boolean | void export type CustomNotification = Partial> @@ -177,7 +192,19 @@ export type Notification = { export type NotificationType = 'pending' | 'success' | 'error' | 'hint' -export declare type Network = 'main' | 'testnet' | 'ropsten' | 'rinkeby' | 'goerli' | 'kovan' | 'xdai' | 'bsc-main' | 'matic-main' | 'fantom-main' | 'matic-mumbai' | 'local'; +export declare type Network = + | 'main' + | 'testnet' + | 'ropsten' + | 'rinkeby' + | 'goerli' + | 'kovan' + | 'xdai' + | 'bsc-main' + | 'matic-main' + | 'fantom-main' + | 'matic-mumbai' + | 'local' export interface UpdateNotification { (notificationObject: CustomNotification): { @@ -187,28 +214,26 @@ export interface UpdateNotification { } ``` -Notify can be used to deliver custom DApp notifications by passing a `CustomNotification` object to the `customNotification` action. This will return an `UpdateNotification` type. - This `UpdateNotification` will return an `update` function that can be passed a new `CustomNotification` to update the existing notification. - The `customNotification` method also returns a `dismiss` method that is called without any parameters to dismiss the notification. - +Notify can be used to deliver custom DApp notifications by passing a `CustomNotification` object to the `customNotification` action. This will return an `UpdateNotification` type. +This `UpdateNotification` will return an `update` function that can be passed a new `CustomNotification` to update the existing notification. +The `customNotification` method also returns a `dismiss` method that is called without any parameters to dismiss the notification. + ```typescript - const { update, dismiss } = - onboard.state.actions.customNotification({ - type: 'pending', - message: - 'This is a custom DApp pending notification to use however you want', - autoDismiss: 0 - }) - setTimeout( - () => - update({ - eventCode: 'dbUpdateSuccess', - message: 'Updated status for custom notification', - type: 'success', - autoDismiss: 8000 - }), - 4000 - ) +const { update, dismiss } = onboard.state.actions.customNotification({ + type: 'pending', + message: 'This is a custom DApp pending notification to use however you want', + autoDismiss: 0 +}) +setTimeout( + () => + update({ + eventCode: 'dbUpdateSuccess', + message: 'Updated status for custom notification', + type: 'success', + autoDismiss: 8000 + }), + 4000 +) ``` ### Initialization Example @@ -273,15 +298,31 @@ const onboard = Onboard({ }, apiKey: 'xxx387fb-bxx1-4xxc-a0x3-9d37e426xxxx' notify: { - enabled: true, - transactionHandler: transaction => { - console.log({ transaction }) - if (transaction.eventCode === 'txPool') { - return { - type: 'success', - message: 'Your transaction from #1 DApp is in the mempool', + desktop: { + enabled: true, + transactionHandler: transaction => { + console.log({ transaction }) + if (transaction.eventCode === 'txPool') { + return { + type: 'success', + message: 'Your transaction from #1 DApp is in the mempool', + } } - } + }, + position: 'bottomLeft' + }, + mobile: { + enabled: true, + transactionHandler: transaction => { + console.log({ transaction }) + if (transaction.eventCode === 'txPool') { + return { + type: 'success', + message: 'Your transaction from #1 DApp is in the mempool', + } + } + }, + position: 'topRight' } }, accountCenter: { @@ -309,7 +350,7 @@ const onboard = Onboard({ }, watched: { // Any words in brackets can be re-ordered or removed to fit your dapps desired verbiage - "txPool": "Your account is {verb} {formattedValue} {asset} {preposition} {counterpartyShortened}" + "txPool": "Your account is {verb} {formattedValue} {asset} {preposition} {counterpartyShortened}" } } }, @@ -408,7 +449,7 @@ type AppState = { accountCenter: AccountCenter walletModules: WalletModule[] locale: Locale - notify: NotifyOptions + notify: Notify notifications: Notification[] } @@ -618,6 +659,9 @@ The Onboard styles can customized via [CSS variables](https://developer.mozilla. --onboard-warning-600: #cc8c00; --onboard-warning-700: #664600; + /* CUSTOMIZE ACCOUNT CENTER STACK POSITIONING*/ + --account-center-z-index + /* CUSTOMIZE SECTIONS OF THE CONNECT MODAL */ --onboard-connect-content-width --onboard-connect-content-height diff --git a/packages/core/package.json b/packages/core/package.json index f2d138f5f..5651b107a 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@web3-onboard/core", - "version": "2.3.0", + "version": "2.3.1", "scripts": { "build": "rollup -c", "dev": "rollup -c -w", @@ -41,7 +41,7 @@ "typescript": "^4.5.5" }, "dependencies": { - "@web3-onboard/common": "^2.1.2", + "@web3-onboard/common": "^2.1.3", "bignumber.js": "^9.0.0", "bnc-sdk": "^4.4.1", "bowser": "^2.11.0", diff --git a/packages/core/src/constants.ts b/packages/core/src/constants.ts index 32bed8402..4c37bda6a 100644 --- a/packages/core/src/constants.ts +++ b/packages/core/src/constants.ts @@ -13,7 +13,8 @@ export const APP_INITIAL_STATE: AppState = { }, notify: { enabled: true, - transactionHandler: () => {} + transactionHandler: () => {}, + position: 'topRight' }, notifications: [], locale: '' diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index bf9c0a384..cbd7a22ff 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -4,10 +4,10 @@ import disconnectWallet from './disconnect' import setChain from './chain' import { state } from './store' import { reset$ } from './streams' -import { validateInitOptions } from './validation' +import { validateInitOptions, validateNotify, validateNotifyOptions } from './validation' import initI18N from './i18n' import App from './views/Index.svelte' -import type { InitOptions, OnboardAPI } from './types' +import type { InitOptions, OnboardAPI, Notify } from './types' import { APP_INITIAL_STATE } from './constants' import { configuration, updateConfiguration } from './configuration' @@ -22,7 +22,7 @@ import { import updateBalances from './updateBalances' -const API = { +const API: OnboardAPI = { connectWallet, disconnectWallet, setChain, @@ -34,7 +34,8 @@ const API = { setLocale, updateNotify, customNotification, - updateBalances + updateBalances, + updateAccountCenter } } } @@ -45,7 +46,13 @@ export type { ConnectOptions, DisconnectOptions, WalletState, - ConnectedChain + ConnectedChain, + AccountCenter, + AppState, + CustomNotification, + Notification, + Notify, + UpdateNotification } from './types' export type { EIP1193Provider } from '@web3-onboard/common' @@ -97,7 +104,50 @@ function init(options: InitOptions): OnboardAPI { // update notify if (typeof notify !== undefined) { - updateNotify(notify) + 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 + 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 + } + updateNotify(notify as Notify) + } } if (svelteInstance) { diff --git a/packages/core/src/store/actions.ts b/packages/core/src/store/actions.ts index d7f9061d7..af1304ac6 100644 --- a/packages/core/src/store/actions.ts +++ b/packages/core/src/store/actions.ts @@ -16,7 +16,6 @@ import type { UpdateAccountCenterAction, UpdateWalletAction, WalletState, - NotifyOptions, UpdateNotifyAction, Notification, AddNotificationAction, @@ -24,7 +23,8 @@ import type { UpdateAllWalletsAction, CustomNotification, UpdateNotification, - CustomNotificationUpdate + CustomNotificationUpdate, + Notify } from '../types' import { @@ -33,11 +33,11 @@ import { validateNotification, validateCustomNotification, validateCustomNotificationUpdate, - validateNotifyOptions, validateString, validateWallet, validateWalletInit, - validateUpdateBalances + validateUpdateBalances, + validateNotify } from '../validation' import { @@ -156,8 +156,8 @@ export function updateAccountCenter( dispatch(action as UpdateAccountCenterAction) } -export function updateNotify(update: Partial): void { - const error = validateNotifyOptions(update) +export function updateNotify(update: Partial): void { + const error = validateNotify(update) if (error) { throw error diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 8a883db33..f93df5820 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -46,15 +46,34 @@ export interface InitOptions { /** * Transaction notification options */ - notify?: Partial + notify?: Partial | Partial } export interface OnboardAPI { connectWallet: typeof connect disconnectWallet: typeof disconnect setChain: typeof setChain - state: typeof state + state: { + select: typeof state.select + get: typeof state.get + actions: ExposedActions + } +} + +interface ExposedActions { + setWalletModules: (wallets: WalletInit[]) => void + setLocale: (locale: string) => void + updateNotify: (update: Partial) => void + customNotification: ( + updatedNotification: CustomNotification + ) => { + dismiss: () => void + update: UpdateNotification + } + updateBalances: (addresses?: string[]) => Promise + updateAccountCenter: (update: AccountCenter | Partial) => void } + export interface ConnectOptions { autoSelect?: { label: string; disableModals: boolean } } @@ -120,7 +139,7 @@ export interface AppState { wallets: WalletState[] accountCenter: AccountCenter locale: Locale - notify: NotifyOptions + notify: Notify notifications: Notification[] } @@ -135,11 +154,15 @@ export type Locale = string export type i18nOptions = Record export type i18n = typeof en -export type AccountCenterPosition = - | 'topRight' - | 'bottomRight' - | 'bottomLeft' - | 'topLeft' +export type CommonPositions = +| 'topRight' +| 'bottomRight' +| 'bottomLeft' +| 'topLeft' + +export type AccountCenterPosition = CommonPositions + +export type NotificationPosition = CommonPositions export type AccountCenter = { enabled: boolean @@ -153,7 +176,7 @@ export type AccountCenterOptions = { mobile: Omit } -export type NotifyOptions = { +export type Notify = { /** * Defines whether whether to subscribe to transaction events or not * default: true @@ -168,6 +191,17 @@ export type NotifyOptions = { transactionHandler: ( event: EthereumTransactionData ) => TransactionHandlerReturn + /** + * Position of notifications that defaults to the same position as the + * Account Center (if enabled) of the top right if AC is disabled + * and notifications are enabled (enabled by default with API key) + */ + position?: NotificationPosition +} + +export type NotifyOptions = { + desktop: Notify + mobile: Notify } export type Notification = { @@ -258,7 +292,7 @@ export type SetLocaleAction = { export type UpdateNotifyAction = { type: 'update_notify' - payload: Partial + payload: Partial } export type AddNotificationAction = { diff --git a/packages/core/src/validation.ts b/packages/core/src/validation.ts index a31081cf5..bbdf8f134 100644 --- a/packages/core/src/validation.ts +++ b/packages/core/src/validation.ts @@ -17,7 +17,8 @@ import type { NotifyOptions, Notification, CustomNotification, - CustomNotificationUpdate + CustomNotificationUpdate, + Notify } from './types' const chainId = Joi.string().pattern(/^0x[0-9a-fA-F]+$/) @@ -128,7 +129,7 @@ const walletInit = Joi.array().items(Joi.function()).required() const locale = Joi.string() -const accountCenterPosition = Joi.string().valid( +const commonPositions = Joi.string().valid( 'topRight', 'bottomRight', 'bottomLeft', @@ -137,7 +138,13 @@ const accountCenterPosition = Joi.string().valid( const notify = Joi.object({ transactionHandler: Joi.function(), - enabled: Joi.boolean() + enabled: Joi.boolean(), + position: commonPositions +}) + +const notifyOptions = Joi.object({ + desktop: notify, + mobile: notify }) const initOptions = Joi.object({ @@ -150,15 +157,15 @@ const initOptions = Joi.object({ desktop: Joi.object({ enabled: Joi.boolean(), minimal: Joi.boolean(), - position: accountCenterPosition + position: commonPositions }), mobile: Joi.object({ enabled: Joi.boolean(), minimal: Joi.boolean(), - position: accountCenterPosition + position: commonPositions }) }), - notify + notify: [notifyOptions, notify] }) const connectOptions = Joi.object({ @@ -183,7 +190,7 @@ const setChainOptions = Joi.object({ const accountCenter = Joi.object({ enabled: Joi.boolean(), - position: accountCenterPosition, + position: commonPositions, expanded: Joi.boolean(), minimal: Joi.boolean() }) @@ -287,10 +294,14 @@ export function validateLocale(data: string): ValidateReturn { return validate(locale, data) } +export function validateNotify(data: Partial): ValidateReturn { + return validate(notify, data) +} + export function validateNotifyOptions( data: Partial ): ValidateReturn { - return validate(notify, data) + return validate(notifyOptions, data) } export function validateTransactionHandlerReturn( diff --git a/packages/core/src/views/Index.svelte b/packages/core/src/views/Index.svelte index f033f1477..adcb618dc 100644 --- a/packages/core/src/views/Index.svelte +++ b/packages/core/src/views/Index.svelte @@ -17,8 +17,7 @@ const notify$ = state .select('notify') .pipe(startWith(state.get().notify), shareReplay(1)) - - const accountCenterPositions = { + const positioningDefaults = { topLeft: 'top: 0; left: 0;', topRight: 'top: 0; right: 0;', bottomRight: 'bottom: 0; right: 0;', @@ -258,6 +257,10 @@ touch-action: none; } + .z-indexed { + z-index: var(--account-center-z-index); + } + @media all and (min-width: 428px) { .container { max-width: 348px; @@ -277,19 +280,47 @@ {/if} -{#if ($notify$.enabled || $accountCenter$.enabled) && $wallets$.length} +{#if $notify$.enabled && $accountCenter$.enabled && $wallets$.length}
- {#if $notify$.enabled && $accountCenter$.position.includes('bottom')} - + {#if $notify$.position.includes('bottom') && $accountCenter$.position.includes('bottom') && (device.type === 'mobile' || $accountCenter$.position === $notify$.position)} + {/if} +
+ +
+ {#if $notify$.position.includes('top') && $accountCenter$.position.includes('top') && (device.type === 'mobile' || $accountCenter$.position === $notify$.position)} + + {/if} +
+{/if} +{#if $accountCenter$.enabled && (!$notify$.enabled || ($notify$.position !== $accountCenter$.position && device.type !== 'mobile')) && $wallets$.length} +
{/if}
- - {#if $notify$.enabled && $accountCenter$.position.includes('top')} - - {/if} +
+{/if} +{#if $notify$.enabled && (!$accountCenter$.enabled || ($notify$.position !== $accountCenter$.position && device.type !== 'mobile') || ($notify$.position.includes('top') && $accountCenter$.position.includes('bottom')) || ($notify$.position.includes('bottom') && $accountCenter$.position.includes('top'))) && $wallets$.length} +
+
{/if} diff --git a/packages/core/src/views/notify/Index.svelte b/packages/core/src/views/notify/Index.svelte index 272722e02..5e5f31213 100644 --- a/packages/core/src/views/notify/Index.svelte +++ b/packages/core/src/views/notify/Index.svelte @@ -6,12 +6,16 @@ import { state } from '../../store' import { shareReplay, startWith } from 'rxjs/operators' import Notification from './Notification.svelte' + import { configuration } from '../../configuration' + + const { device } = configuration const accountCenter$ = state .select('accountCenter') .pipe(startWith(state.get().accountCenter), shareReplay(1)) export let position: string + export let sharedContainer: boolean let x: number let y: number @@ -116,7 +120,13 @@ style={`${ position.includes('top') ? 'justify-content:flex-start;' : '' }; max-height: calc(100vh - ${ - !$accountCenter$.expanded ? '82px' : '412px' + $accountCenter$.expanded + ? '412px' + : sharedContainer && device.type !== 'mobile' + ? '82px' + : !sharedContainer && device.type === 'mobile' + ? '108px' + : '24px' })`} > {#each $notifications$ as notification (notification.key)} diff --git a/packages/dcent/package.json b/packages/dcent/package.json index a92d06ac2..743361caf 100644 --- a/packages/dcent/package.json +++ b/packages/dcent/package.json @@ -1,6 +1,6 @@ { "name": "@web3-onboard/dcent", - "version": "2.0.2", + "version": "2.0.3", "description": "D'CENT module for web3-onboard", "module": "dist/index.js", "typings": "dist/index.d.ts", @@ -18,7 +18,7 @@ "typescript": "^4.5.5" }, "dependencies": { - "@web3-onboard/common": "^2.1.2", + "@web3-onboard/common": "^2.1.3", "@ethereumjs/common": "^2.6.1", "@ethereumjs/tx": "^3.4.0", "@ethersproject/providers": "^5.5.0", diff --git a/packages/demo/package.json b/packages/demo/package.json index 32d5d5ff3..9c80a9074 100644 --- a/packages/demo/package.json +++ b/packages/demo/package.json @@ -1,6 +1,6 @@ { "name": "demo", - "version": "2.0.3", + "version": "2.0.5", "devDependencies": { "assert": "^2.0.0", "buffer": "^6.0.3", @@ -22,21 +22,21 @@ "webpack-dev-server": "4.7.4" }, "dependencies": { - "@web3-onboard/coinbase": "^2.0.5", - "@web3-onboard/core": "^2.3.0", - "@web3-onboard/dcent": "^2.0.2", - "@web3-onboard/fortmatic": "^2.0.4", - "@web3-onboard/gnosis": "^2.0.3", - "@web3-onboard/injected-wallets": "^2.0.10", - "@web3-onboard/keepkey": "^2.1.2", - "@web3-onboard/keystone": "^2.1.3", - "@web3-onboard/ledger": "^2.1.2", - "@web3-onboard/magic": "^2.0.5", - "@web3-onboard/portis": "^2.0.2", - "@web3-onboard/torus": "^2.0.3", - "@web3-onboard/trezor": "^2.1.2", - "@web3-onboard/walletconnect": "^2.0.3", - "@web3-onboard/web3auth": "^2.0.1", + "@web3-onboard/coinbase": "^2.0.6", + "@web3-onboard/core": "^2.3.1", + "@web3-onboard/dcent": "^2.0.3", + "@web3-onboard/fortmatic": "^2.0.5", + "@web3-onboard/gnosis": "^2.0.4", + "@web3-onboard/injected-wallets": "^2.0.11", + "@web3-onboard/keepkey": "^2.1.3", + "@web3-onboard/keystone": "^2.1.4", + "@web3-onboard/ledger": "^2.1.3", + "@web3-onboard/magic": "^2.0.6", + "@web3-onboard/portis": "^2.0.3", + "@web3-onboard/torus": "^2.0.4", + "@web3-onboard/trezor": "^2.1.3", + "@web3-onboard/walletconnect": "^2.0.4", + "@web3-onboard/web3auth": "^2.0.2", "vconsole": "^3.9.5" }, "license": "MIT", diff --git a/packages/demo/src/App.svelte b/packages/demo/src/App.svelte index 272f1e4f1..786d6d28c 100644 --- a/packages/demo/src/App.svelte +++ b/packages/demo/src/App.svelte @@ -139,6 +139,12 @@ label: 'Polygon', rpcUrl: 'https://matic-mainnet.chainstacklabs.com' }, + { + id: '0x13881', + token: 'MATIC', + label: 'Polygon - Mumbai', + rpcUrl: 'https://matic-mumbai.chainstacklabs.com ' + }, { id: '0xa', token: 'OETH', @@ -166,7 +172,7 @@ // // example customizing account center accountCenter: { desktop: { - position: 'topRight', + position: 'topLeft', enabled: true, minimal: false } @@ -182,29 +188,33 @@ } }, notify: { - enabled: true, - transactionHandler: transaction => { - console.log({ transaction }) - // if (transaction.eventCode === 'txConfirmed') { - // return { - // type: 'error', - // message: 'Your in the pool, hope you brought a towel!', - // autoDismiss: 0, - // id: '123', - // key: '321', - // onClick: () => - // window.open(`https://rinkeby.etherscan.io/tx/${transaction.hash}`) - // } - // } - // if (transaction.eventCode === 'txPool') { - // return { - // type: 'hint', - // message: 'Your in the pool, hope you brought a towel!', - // autoDismiss: 0, - // link: `https://ropsten.etherscan.io/tx/${transaction.hash}` - // } - // } - } + desktop: { + enabled: true, + transactionHandler: transaction => { + console.log({ transaction }) + // if (transaction.eventCode === 'txConfirmed') { + // return { + // type: 'error', + // message: 'Your in the pool, hope you brought a towel!', + // autoDismiss: 0, + // id: '123', + // key: '321', + // onClick: () => + // window.open(`https://rinkeby.etherscan.io/tx/${transaction.hash}`) + // } + // } + // if (transaction.eventCode === 'txPool') { + // return { + // type: 'hint', + // message: 'Your in the pool, hope you brought a towel!', + // autoDismiss: 0, + // link: `https://ropsten.etherscan.io/tx/${transaction.hash}` + // } + // } + }, + position: 'topRight' + }, + }, // Sign up for your free api key at www.Blocknative.com apiKey: 'xxxxxx-bf21-42ec-a093-9d37e426xxxx' @@ -220,11 +230,27 @@ const signature = await signer.signTransaction({ to: '', - value: 1000000000000000 + value: 100000000000000 }) + console.log(signature) } + let toAddress + const sendTransaction = async provider => { + const ethersProvider = new ethers.providers.Web3Provider(provider, 'any') + + const signer = ethersProvider.getSigner() + + const txn = await signer.sendTransaction({ + to: toAddress, + value: 100000000000000 + }) + + const receipt = await txn.wait() + console.log(receipt) + } + const signMessage = async (provider, address) => { const ethersProvider = new ethers.providers.Web3Provider(provider, 'any') @@ -441,6 +467,18 @@ +
+ + +
+