Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/connect-evm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- **BREAKING:** `disconnect()` now revokes the entire session instead of only its `eip155:*` scopes ([#344](https://github.com/MetaMask/connect-monorepo/pull/344)). The wallet may grant scopes beyond those requested (e.g. networks pre-selected on the connect prompt), and revoking only the `eip155:*` scopes stranded those extras in a session the wallet still reported as connected. This matches the legacy EIP-1193 behavior where `wallet_revokePermissions` revokes the origin's entire permission.

## [2.1.1]

### Added
Expand Down
16 changes: 10 additions & 6 deletions packages/connect-evm/src/connect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1262,7 +1262,7 @@ describe('MetamaskConnectEVM', () => {
});

describe('disconnect', () => {
it('calls core.disconnect with all eip155 scopes from the current session', async () => {
it('calls core.disconnect with no scopes to revoke the entire session', async () => {
const mockCore = createMockCore();
mockCore.storage.adapter.get.mockResolvedValue(JSON.stringify('0x1'));
const client = await MetamaskConnectEVM.create({ core: mockCore });
Expand All @@ -1279,6 +1279,11 @@ describe('MetamaskConnectEVM', () => {
notifications: [],
accounts: ['eip155:137:0x1234567890123456789012345678901234567890'],
},
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp': {
methods: [],
notifications: [],
accounts: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:1234567890'],
},
},
};
mockCore.emit('wallet_sessionChanged', session);
Expand All @@ -1288,12 +1293,11 @@ describe('MetamaskConnectEVM', () => {

await client.disconnect();

// Called with no scopes so the wallet revokes the whole session,
// including scopes granted beyond the eip155 scopes this client
// requested (e.g. networks pre-selected by the wallet).
expect(mockCore.disconnect).toHaveBeenCalledTimes(1);
const [scopes] = mockCore.disconnect.mock.calls[0];
expect(scopes).toEqual(
expect.arrayContaining(['eip155:1', 'eip155:137']),
);
expect(scopes).toHaveLength(2);
expect(mockCore.disconnect).toHaveBeenCalledWith();
});
});

Expand Down
23 changes: 11 additions & 12 deletions packages/connect-evm/src/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,7 @@ import type {
ProviderRequest,
ProviderRequestInterceptor,
} from './types';
import {
getEthAccounts,
getPermittedEthChainIds,
parseScopeString,
} from './utils/caip';
import { getEthAccounts, getPermittedEthChainIds } from './utils/caip';
import {
isAccountsRequest,
isAddChainRequest,
Expand Down Expand Up @@ -601,18 +597,21 @@ export class MetamaskConnectEVM {
/**
* Disconnects from the wallet by revoking the session and cleaning up event listeners.
*
* The entire session is revoked rather than just its `eip155:*` scopes. The
* wallet may grant additional scopes beyond those requested (e.g. it
* pre-selects all of the user's enabled networks for EIP-1193 compatible
* connections), and no other client on the page is responsible for cleaning
* those up. Revoking only the `eip155:*` scopes would strand the extra
* scopes in a session that the wallet still reports as connected. This also
* matches the legacy EIP-1193 behavior, where `wallet_revokePermissions`
* revokes the origin's entire CAIP-25 permission.
*
* @returns A promise that resolves when disconnection is complete
*/
async disconnect(): Promise<void> {
logger('request: disconnect');

const sessionScopes = this.#sessionScopes;
const eip155Scopes = Object.keys(sessionScopes).filter((scope) => {
const { namespace } = parseScopeString(scope as Scope);
return namespace === 'eip155';
});

await this.#core.disconnect(eip155Scopes as Scope[]);
await this.#core.disconnect();
this.#onDisconnect();
this.#clearConnectionState();

Expand Down
Loading