-
-
Notifications
You must be signed in to change notification settings - Fork 2
feat: Add MM Connect integration #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e182773
36b291c
1a133d1
b585136
814600a
bb1b39b
7277577
dbde246
1e97a5c
0ebf36c
62c642a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| import type { MultichainCore, Scope } from '@metamask/connect-multichain'; | ||
| import { createMetamaskConnect } from '@metamask/connect-multichain'; | ||
| import type { CaipAccountId } from '@metamask/utils'; | ||
|
|
||
| import type { Provider } from './Provider'; | ||
|
|
||
| type NotificationCallback = (notification: any) => void; | ||
|
|
||
| class MetaMaskConnectProvider implements Provider { | ||
| #mmConnect: MultichainCore | null = null; | ||
|
|
||
| #notificationCallbacks: Set<NotificationCallback> = new Set(); | ||
|
|
||
| #walletSession: unknown = { sessionScopes: {} }; | ||
|
|
||
| async connect(): Promise<boolean> { | ||
| if (this.#mmConnect) { | ||
| this.disconnect(); | ||
| } | ||
|
|
||
| this.#mmConnect = await createMetamaskConnect({ | ||
| dapp: { | ||
| name: 'MultichainTest Dapp', | ||
| url: 'https://metamask.github.io/test-dapp-multichain/latest/', | ||
| }, | ||
| transport: { | ||
| onNotification: (notification: any) => { | ||
| if (notification.method === 'wallet_sessionChanged') { | ||
| this.#walletSession = notification.params; | ||
| } | ||
| this.#notifyCallbacks(notification); | ||
| }, | ||
| }, | ||
| ui: { | ||
| preferDesktop: false, | ||
| preferExtension: false, | ||
| }, | ||
| }); | ||
|
|
||
| await this.#mmConnect?.connect(['eip155:1'], []); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Session Initialization ConflictThe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Redundant Connection Interferes with Multi-Chain SupportThe |
||
|
|
||
| return true; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Metamask Connection Initialization FailureThe |
||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| disconnect(): void { | ||
| if (this.#mmConnect !== null) { | ||
| this.#mmConnect.disconnect().catch(console.error); | ||
| this.#mmConnect = null; | ||
| } | ||
| } | ||
|
|
||
| isConnected(): boolean { | ||
| return Boolean(this.#mmConnect); | ||
| } | ||
|
|
||
| async request(request: { method: string; params: any }): Promise<any> { | ||
| if (request.method === 'wallet_invokeMethod') { | ||
| return this.#mmConnect?.invokeMethod(request.params); | ||
| } | ||
| if (request.method === 'wallet_getSession') { | ||
| return this.#walletSession; | ||
| } | ||
| if (request.method === 'wallet_revokeSession') { | ||
| this.disconnect(); | ||
| } | ||
| if (request.method === 'wallet_createSession') { | ||
| const requestedScopes = Object.keys({ | ||
| ...request.params.optionalScopes, | ||
| ...request.params.requiredScopes, | ||
| }) as unknown as Scope[]; | ||
|
|
||
| const requestedAccounts = new Set<CaipAccountId>(); | ||
| Object.values(request.params.optionalScopes).forEach((scopeObject) => { | ||
| const { accounts } = scopeObject as { accounts: CaipAccountId[] }; | ||
| accounts.forEach((account) => requestedAccounts.add(account)); | ||
| }); | ||
| await this.#mmConnect?.connect( | ||
| requestedScopes, | ||
| Array.from(requestedAccounts), | ||
| ); | ||
| return this.#walletSession; | ||
| } | ||
| return Promise.resolve(null); | ||
| } | ||
|
|
||
| onNotification(callback: NotificationCallback): void { | ||
| this.#notificationCallbacks.add(callback); | ||
| } | ||
|
|
||
| removeNotificationListener(callback: NotificationCallback): void { | ||
| this.#notificationCallbacks.delete(callback); | ||
| } | ||
|
|
||
| removeAllNotificationListeners() { | ||
| this.#notificationCallbacks.forEach( | ||
| this.removeNotificationListener.bind(this), | ||
| ); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: Concurrent Modification in Notification Callback RemovalThe |
||
|
|
||
| #notifyCallbacks(notification: any): void { | ||
| this.#notificationCallbacks.forEach((callback) => { | ||
| try { | ||
| callback(notification); | ||
| } catch (error) { | ||
| console.error('Error in notification callback:', error); | ||
| } | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| export default MetaMaskConnectProvider; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Duplicate Connection Logic in Provider Initialization
The line
await this.#mmConnect?.connect(['eip155:1'], []);in theconnect()method hardcodes the initial connection with scope 'eip155:1'. This duplicates the connection logic that should only occur in therequest()method when handling 'wallet_createSession'. This causes the connection to be established twice: once with the hardcoded scope during provider initialization, and again with the actual user-provided scopes when createSession is called. The hardcoded connection call should be removed from the connect() method.