diff --git a/packages/core/package.json b/packages/core/package.json index 2717988e4..3ccad440b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@web3-onboard/core", - "version": "2.8.5", + "version": "2.9.0-alpha.1", "description": "Web3-Onboard makes it simple to connect Ethereum hardware and software wallets to your dapp. Features standardized spec compliant web3 providers for all supported wallets, framework agnostic modern javascript UI with code splitting, CSS customization, multi-chain and multi-account support, reactive wallet state subscriptions and real-time transaction state change notifications.", "keywords": [ "Ethereum", diff --git a/packages/core/src/provider.ts b/packages/core/src/provider.ts index 21262163f..4da16c9e0 100644 --- a/packages/core/src/provider.ts +++ b/packages/core/src/provider.ts @@ -2,6 +2,13 @@ import { fromEventPattern, Observable } from 'rxjs' import { filter, takeUntil, take, share, switchMap } from 'rxjs/operators' import partition from 'lodash.partition' import { providers } from 'ethers' +import { weiToEth } from '@web3-onboard/common' +import { disconnectWallet$ } from './streams.js' +import { updateAccount, updateWallet } from './store/actions.js' +import { validEnsChain } from './utils.js' +import disconnect from './disconnect.js' +import { state } from './store/index.js' +import { getBlocknativeSdk } from './services.js' import type { ChainId, @@ -14,14 +21,14 @@ import type { SelectAccountsRequest } from '@web3-onboard/common' -import { weiToEth } from '@web3-onboard/common' -import { disconnectWallet$ } from './streams.js' -import type { Account, Address, Balances, Ens, WalletState } from './types.js' -import { updateAccount, updateWallet } from './store/actions.js' -import { validEnsChain } from './utils.js' -import disconnect from './disconnect.js' -import { state } from './store/index.js' -import { getBlocknativeSdk } from './services.js' +import type { + Account, + Address, + Balances, + Ens, + WalletPermission, + WalletState +} from './types.js' export const ethersProviders: { [key: string]: providers.StaticJsonRpcProvider @@ -112,6 +119,17 @@ export function trackWallet( // when account changed, set it to first account and subscribe to events accountsChanged$.subscribe(async ([address]) => { + // sync accounts with internal state + // in the case of an account has been manually disconnected + try { + await syncWalletConnectedAccounts(label) + } catch (error) { + console.warn( + 'Web3Onboard: Error whilst trying to sync connected accounts:', + error + ) + } + // no address, then no account connected, so disconnect wallet // this could happen if user locks wallet, // or if disconnects app from wallet @@ -180,11 +198,12 @@ export function trackWallet( const balanceProm = getBalance(address, chain) const account = accounts.find(account => account.address === address) - const ensProm = account.ens - ? Promise.resolve(account.ens) - : validEnsChain(connectedWalletChain.id) - ? getEns(address, chain) - : Promise.resolve(null) + const ensProm = + account && account.ens + ? Promise.resolve(account.ens) + : validEnsChain(connectedWalletChain.id) + ? getEns(address, chain) + : Promise.resolve(null) return Promise.all([Promise.resolve(address), balanceProm, ensProm]) }) @@ -390,3 +409,41 @@ export function addNewChain( ] }) } + +export async function getPermissions( + provider: EIP1193Provider +): Promise { + try { + const permissions = (await provider.request({ + method: 'wallet_getPermissions' + })) as WalletPermission[] + + return Array.isArray(permissions) ? permissions : [] + } catch (error) { + return [] + } +} + +export async function syncWalletConnectedAccounts( + label: WalletState['label'] +): Promise { + const wallet = state.get().wallets.find(wallet => wallet.label === label) + const permissions = await getPermissions(wallet.provider) + const accountsPermissions = permissions.find( + ({ parentCapability }) => parentCapability === 'eth_accounts' + ) + + if (accountsPermissions) { + const { value: connectedAccounts } = accountsPermissions.caveats.find( + ({ type }) => type === 'restrictReturnedAccounts' + ) || { value: null } + + if (connectedAccounts) { + const syncedAccounts = wallet.accounts.filter(({ address }) => + connectedAccounts.includes(address) + ) + + updateWallet(wallet.label, { ...wallet, accounts: syncedAccounts }) + } + } +} diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index fd0659d92..65b591ba4 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -343,3 +343,15 @@ export type DeviceNotBrowser = { os: null browser: null } + +export type WalletPermission = { + id: string + parentCapability: string + invoker: string + caveats: { + type: string + value: string[] + }[] + + date: number +}