-
Notifications
You must be signed in to change notification settings - Fork 2
Jl/wip mm connect #41
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
| @@ -1,12 +1,13 @@ | ||
| import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react'; | ||
| import { WalletModalProvider } from '@solana/wallet-adapter-react-ui'; | ||
| import { type FC, useMemo } from 'react'; | ||
| import { type FC, useEffect, useMemo, useRef } from 'react'; | ||
|
|
||
| import '@solana/wallet-adapter-react-ui/styles.css'; | ||
| import { TestPage } from './pages/TestPage'; | ||
|
|
||
| import { registerSolanaWalletStandard } from '@metamask/solana-wallet-standard'; | ||
| import { CoinbaseWalletAdapter, PhantomWalletAdapter, SolflareWalletAdapter } from '@solana/wallet-adapter-wallets'; | ||
| import { useSDK } from './SDKProvider'; | ||
| import { EndpointProvider, useEndpoint } from './context/EndpointProvider'; | ||
| import { TestPage } from './pages/TestPage'; | ||
|
|
||
| const AppContent: FC = () => { | ||
| const { endpoint } = useEndpoint(); | ||
|
|
@@ -16,6 +17,24 @@ const AppContent: FC = () => { | |
| [endpoint], | ||
| ); | ||
|
|
||
| const { getProvider } = useSDK(); | ||
| const registered = useRef(false); | ||
| useEffect(() => { | ||
| if (registered.current) { | ||
| return; | ||
| } | ||
| registered.current = true; | ||
| (async () => { | ||
| // TODO: fix this | ||
| await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for the SDK to be initialized | ||
|
|
||
| const provider = await getProvider(); | ||
| if (provider) { | ||
| registerSolanaWalletStandard({ client: provider }); | ||
| } | ||
| })(); | ||
|
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. Unhandled promise rejection when
|
||
| }, [getProvider]); | ||
|
|
||
| return ( | ||
| <ConnectionProvider endpoint={endpoint} config={{ commitment: 'confirmed' }}> | ||
| <WalletProvider wallets={wallets} autoConnect={true}> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| /* eslint-disable */ | ||
|
|
||
| import { | ||
| type InvokeMethodOptions, | ||
| type MultichainCore, | ||
| type SDKState, | ||
| type Scope, | ||
| type SessionData, | ||
| createMultichainClient, | ||
| getInfuraRpcUrls, | ||
| } from '@metamask/connect-multichain'; | ||
| import type { MultichainApiClient } from '@metamask/multichain-api-client'; | ||
| import type { CaipAccountId } from '@metamask/utils'; | ||
| import type React from 'react'; | ||
| import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'; | ||
|
|
||
| const METAMASK_PROD_CHROME_ID = 'nkbihfbeogaeaoehlefnkodbefgpgknn'; | ||
|
|
||
| const SDKContext = createContext< | ||
| | { | ||
| session: SessionData | undefined; | ||
| state: SDKState; | ||
| error: Error | null; | ||
| connect: (scopes: Scope[], caipAccountIds: CaipAccountId[]) => Promise<void>; | ||
| disconnect: () => Promise<void>; | ||
| invokeMethod: (options: InvokeMethodOptions) => Promise<any>; | ||
| getProvider: () => Promise<MultichainApiClient>; | ||
| } | ||
| | undefined | ||
| >(undefined); | ||
|
|
||
| export const SDKProvider = ({ children }: { children: React.ReactNode }) => { | ||
| const [state, setState] = useState<SDKState>('pending'); | ||
| const [session, setSession] = useState<SessionData | undefined>(undefined); | ||
| const [error, setError] = useState<Error | null>(null); | ||
|
|
||
| const sdkRef = useRef<Promise<MultichainCore>>(undefined); | ||
|
|
||
| useEffect(() => { | ||
| if (!sdkRef.current) { | ||
| sdkRef.current = createMultichainClient({ | ||
| dapp: { | ||
| name: 'playground', | ||
| url: 'https://playground.metamask.io', | ||
| }, | ||
| api: { | ||
| supportedNetworks: getInfuraRpcUrls(process.env.INFURA_API_KEY || ''), | ||
|
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. Environment variable inaccessible in Vite browser contextMedium Severity The code uses |
||
| }, | ||
| transport: { | ||
| extensionId: METAMASK_PROD_CHROME_ID, | ||
| onNotification: (notification: unknown) => { | ||
| const payload = notification as Record<string, unknown>; | ||
| if ( | ||
| payload.method === 'wallet_sessionChanged' || | ||
| payload.method === 'wallet_createSession' || | ||
| payload.method === 'wallet_getSession' | ||
| ) { | ||
| setSession(payload.params as SessionData); | ||
| } else if (payload.method === 'stateChanged') { | ||
| setState(payload.params as SDKState); | ||
| } | ||
| }, | ||
| }, | ||
| }); | ||
| } | ||
| }, []); | ||
|
|
||
| const disconnect = useCallback(async () => { | ||
| try { | ||
| if (!sdkRef.current) { | ||
| throw new Error('SDK not initialized'); | ||
| } | ||
| const sdkInstance = await sdkRef.current; | ||
| return sdkInstance.disconnect(); | ||
| } catch (error) { | ||
| setError(error as Error); | ||
| } | ||
| }, []); | ||
|
|
||
| const connect = useCallback(async (scopes: Scope[], caipAccountIds: CaipAccountId[]) => { | ||
| try { | ||
| if (!sdkRef.current) { | ||
| throw new Error('SDK not initialized'); | ||
| } | ||
| const sdkInstance = await sdkRef.current; | ||
| await sdkInstance.connect(scopes, caipAccountIds); | ||
| } catch (error) { | ||
| setError(error as Error); | ||
| } | ||
| }, []); | ||
|
|
||
| const invokeMethod = useCallback(async (options: InvokeMethodOptions) => { | ||
| try { | ||
| if (!sdkRef.current) { | ||
| throw new Error('SDK not initialized'); | ||
| } | ||
| const sdkInstance = await sdkRef.current; | ||
| return sdkInstance.invokeMethod(options); | ||
| } catch (error) { | ||
| setError(error as Error); | ||
| } | ||
| }, []); | ||
|
|
||
| const getProvider = useCallback(async () => { | ||
| if (!sdkRef.current) { | ||
| throw new Error('SDK not initialized'); | ||
| } | ||
| const sdkInstance = await sdkRef.current; | ||
| return sdkInstance.provider as MultichainApiClient; | ||
| }, []); | ||
|
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. Inconsistent error handling in
|
||
|
|
||
| return ( | ||
| <SDKContext.Provider | ||
| value={{ | ||
| session, | ||
| state, | ||
| error, | ||
| connect, | ||
| disconnect, | ||
| invokeMethod, | ||
| getProvider, | ||
| }} | ||
| > | ||
| {children} | ||
| </SDKContext.Provider> | ||
| ); | ||
| }; | ||
|
|
||
| export const useSDK = () => { | ||
| const context = useContext(SDKContext); | ||
| if (context === undefined) { | ||
| throw new Error('useSDK must be used within a SDKProvider'); | ||
| } | ||
| return context; | ||
| }; | ||
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.
Local file dependencies break builds in non-local environments
High Severity
The
resolutionsanddependenciescontain local file paths likefile:../connect-monorepo/packages/connect-multichainthat reference a sibling directory. These paths will fail in CI/CD pipelines, other developers' machines, and production builds since the expected local directory structure won't exist. This appears to be development-time configuration that was accidentally included in the PR.