From 1cffd62030c4c9e1b58ee932a9fc9cc9d7f6431d Mon Sep 17 00:00:00 2001 From: Alexandra Tran Date: Tue, 16 Jul 2024 11:43:40 -0700 Subject: [PATCH] revert wallet docs --- wallet/concepts/sdk/android.md | 8 +- wallet/concepts/sdk/connections.md | 11 +- wallet/concepts/sdk/index.md | 40 ++-- wallet/concepts/smart-contracts.md | 2 +- wallet/concepts/wallet-api.md | 10 +- wallet/concepts/wallet-interoperability.md | 16 +- wallet/how-to/connect/access-accounts.md | 44 ++-- wallet/how-to/connect/index.md | 83 +++---- wallet/how-to/display/tokens.md | 24 +-- wallet/how-to/manage-networks/add-network.md | 4 +- .../how-to/manage-networks/detect-network.md | 6 +- wallet/how-to/manage-permissions.md | 20 +- wallet/how-to/onboard-users.md | 190 ++++++++-------- wallet/how-to/run-devnet.md | 90 ++++---- wallet/how-to/secure-dapp.md | 6 +- wallet/how-to/sign-data/index.md | 58 +++-- wallet/how-to/sign-data/siwe.md | 24 +-- .../use-sdk/3rd-party-libraries/wagmi.md | 20 +- .../3rd-party-libraries/web3-onboard.md | 10 +- .../use-sdk/gaming/unity/connect-and-sign.md | 46 ++-- wallet/how-to/use-sdk/gaming/unity/dweb.md | 4 +- wallet/how-to/use-sdk/gaming/unity/index.md | 11 +- wallet/how-to/use-sdk/gaming/unity/infura.md | 10 +- .../smart-contracts/contract-interface.md | 118 +++++----- .../smart-contracts/contract-proxy-class.md | 2 +- .../gaming/unity/smart-contracts/index.md | 2 +- wallet/how-to/use-sdk/gaming/unreal-engine.md | 2 +- .../javascript/batch-json-rpc-requests.md | 14 +- .../use-sdk/javascript/connect-and-sign.md | 30 +-- .../javascript/display-custom-modals.md | 37 ++-- wallet/how-to/use-sdk/javascript/index.md | 16 +- .../javascript/make-read-only-requests.md | 4 +- wallet/how-to/use-sdk/javascript/nodejs.md | 16 +- .../javascript/other-web-frameworks.md | 12 +- wallet/how-to/use-sdk/javascript/pure-js.md | 6 +- .../how-to/use-sdk/javascript/react-native.md | 142 ++++++------ .../how-to/use-sdk/javascript/react/index.md | 14 +- .../use-sdk/javascript/react/react-ui.md | 37 ++-- wallet/how-to/use-sdk/mobile/android.md | 9 +- wallet/how-to/use-sdk/mobile/ios.md | 4 +- wallet/index.mdx | 24 +-- wallet/reference/new-reference.mdx | 6 +- wallet/reference/provider-api.md | 52 ++--- wallet/reference/sdk-js-options.md | 6 +- wallet/tutorials/javascript-dapp-simple.md | 112 +++++----- wallet/tutorials/react-dapp-global-state.md | 204 +++++++----------- wallet/tutorials/react-dapp-local-state.md | 75 +++---- yarn.lock | 6 +- 48 files changed, 799 insertions(+), 888 deletions(-) diff --git a/wallet/concepts/sdk/android.md b/wallet/concepts/sdk/android.md index 022adbd8e90..d6ed5282fb9 100644 --- a/wallet/concepts/sdk/android.md +++ b/wallet/concepts/sdk/android.md @@ -13,11 +13,10 @@ The [architecture](#architecture) and [connection flow](#connection-flow) of the Android SDK differs from the other SDK platforms. :::tip Get started - - Get started by [setting up the SDK in your Android dapp](../../how-to/use-sdk/mobile/android.md). - See the [example Android dapp](https://github.com/MetaMask/metamask-android-sdk/tree/main/app) in the Android SDK GitHub repository for advanced use cases. - ::: +::: ## Architecture @@ -53,7 +52,8 @@ The following diagram outlines the communication flow between the Android client The flow is as follows: 1. The dapp, with the SDK installed, initiates communication when a user connects to MetaMask. - The dapp deeplinks to MetaMask, and MetaMask sets up the Android Native Module to receive client requests. + The dapp deeplinks to MetaMask, and MetaMask sets up the Android Native Module to receive client requests. 2. The dapp generates an ECIES public/private key pair. - The dapp and MetaMask exchange public keys over IPC. + The dapp and MetaMask exchange public keys over IPC. 3. The dapp and MetaMask perform end-to-end encrypted JSON-RPC calls. + diff --git a/wallet/concepts/sdk/connections.md b/wallet/concepts/sdk/connections.md index 5367e5faac0..efc5a59c2ba 100644 --- a/wallet/concepts/sdk/connections.md +++ b/wallet/concepts/sdk/connections.md @@ -40,16 +40,17 @@ The path first depends on whether the dapp is on a desktop or mobile platform: - If the dapp is on a desktop platform (for example, a desktop web dapp), the dapp shows a modal asking the user to select if they want to connect to MetaMask using the browser extension or MetaMask Mobile. - + - If the user selects extension: - If the extension is not installed, the user is taken to the Chrome extension store to - install it. + install it. - If the extension is installed, the user connects to their MetaMask extension. + - If the user selects MetaMask Mobile: - If MetaMask Mobile is not installed, the user is taken to the app store to install it. - If MetaMask Mobile is installed, [an encrypted connection from the dapp to MetaMask Mobile](#metamask-mobile-connection) is established. - + :::note The choice between the extension and MetaMask Mobile persists until the user or dapp disconnects. At that point, the dapp displays the modal again. @@ -103,11 +104,11 @@ The flow is as follows: 1. The dapp generates a UUID v4 ([Socket.io](https://socket.io/) room ID) and ECIES key pair. 2. The dapp connects to the Socket.io server using the room ID. 3. The dapp sends a deeplink to MetaMask Mobile (either directly, if on mobile, or through a QR - code, if on desktop) containing its ECIES public key and the Socket.io room ID. + code, if on desktop) containing its ECIES public key and the Socket.io room ID. 4. MetaMask Mobile opens the QR code or deeplink and connects to the Socket.io server using the room ID. 5. MetaMask Mobile generates an ECIES key pair. 6. MetaMask Mobile sends its ECIES public key to the dapp using the Socket.io channel, and the two - parties generate a shared secret. + parties generate a shared secret. 7. The dapp and MetaMask Mobile establish an encrypted connection to send JSON-RPC API methods. :::note diff --git a/wallet/concepts/sdk/index.md b/wallet/concepts/sdk/index.md index 4222d2fcba0..c09bd303bdc 100644 --- a/wallet/concepts/sdk/index.md +++ b/wallet/concepts/sdk/index.md @@ -8,8 +8,8 @@ tags: - Unity SDK --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # About MetaMask SDK @@ -33,15 +33,15 @@ MetaMask using the SDK. Most of these features are not available if you only integrate your dapp directly using the [Wallet API](../wallet-api.md). -| Feature | Wallet API only | MetaMask SDK | -| ---------------------------------------------------------------------------------------------------------- | :-------------: | :----------: | -| Connect from a web dapp to the MetaMask extension | ✅ | ✅ | -| Connect from a web dapp to MetaMask Mobile | ❌ | ✅ | -| Connect from desktop, mobile, and gaming dapps to MetaMask Mobile | ❌ | ✅ | -| Use custom RPC methods such as [`connectAndSign`](../../how-to/use-sdk/javascript/connect-and-sign.md) | ❌ | ✅ | -| [Display custom modals](../../how-to/use-sdk/javascript/display-custom-modals.md) in MetaMask | ❌ | ✅ | -| [Make read-only requests](../../how-to/use-sdk/javascript/make-read-only-requests.md) using the Infura API | ❌ | ✅ | -| [Batch multiple RPC requests](../../how-to/use-sdk/javascript/batch-json-rpc-requests.md) | ❌ | ✅ | +| Feature | Wallet API only | MetaMask SDK | +|-----------------------------------------------------------------------------------------------|:---------------:|:------------:| +| Connect from a web dapp to the MetaMask extension | ✅ | ✅ | +| Connect from a web dapp to MetaMask Mobile | ❌ | ✅ | +| Connect from desktop, mobile, and gaming dapps to MetaMask Mobile | ❌ | ✅ | +| Use custom RPC methods such as [`connectAndSign`](../../how-to/use-sdk/javascript/connect-and-sign.md) | ❌ | ✅ | +| [Display custom modals](../../how-to/use-sdk/javascript/display-custom-modals.md) in MetaMask | ❌ | ✅ | +| [Make read-only requests](../../how-to/use-sdk/javascript/make-read-only-requests.md) using the Infura API | ❌ | ✅ | +| [Batch multiple RPC requests](../../how-to/use-sdk/javascript/batch-json-rpc-requests.md) | ❌ | ✅ | ## User experience @@ -61,11 +61,10 @@ to MetaMask Mobile using a QR code.

:::tip Get started - - Get started by [setting up the SDK in your web dapp](../../how-to/use-sdk/javascript/index.md). - See the [example JavaScript dapps](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples) in the JavaScript SDK GitHub repository for advanced use cases. - ::: +::: @@ -82,11 +81,10 @@ This happens for all actions that need user approval.

:::tip Get started - - Get started by [setting up the SDK in your web dapp](../../how-to/use-sdk/javascript/index.md). - See the [example JavaScript dapps](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples) in the JavaScript SDK GitHub repository for advanced use cases. - ::: +:::
@@ -103,11 +101,10 @@ This happens for all actions that need user approval.

:::tip Get started - - Get started by [setting up the SDK in your iOS dapp](../../how-to/use-sdk/mobile/ios.md). - See the [example iOS dapp](https://github.com/MetaMask/metamask-ios-sdk) in the iOS SDK GitHub repository for advanced use cases. - ::: +:::
@@ -124,11 +121,10 @@ This happens for all actions that need user approval.

:::tip Get started - - Get started by [setting up the SDK in your Android dapp](../../how-to/use-sdk/mobile/android.md). - See the [example Android dapp](https://github.com/MetaMask/metamask-android-sdk/tree/main/app) in the Android SDK GitHub repository and the [Android SDK architecture](android.md) for more information. - ::: +:::
@@ -143,11 +139,10 @@ scan with their MetaMask Mobile app.

:::tip Get started - - Get started by [setting up the SDK in your Node.js dapp](../../how-to/use-sdk/javascript/nodejs.md). - See the [example Node.js dapp](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/nodejs) in the Node.js SDK GitHub repository for advanced use cases. - ::: +:::
@@ -163,11 +158,10 @@ It also supports deeplinking on mobile platforms, as demonstrated in the followi

:::tip Get started - - Get started by [setting up the SDK in your Unity game](../../how-to/use-sdk/gaming/unity/index.md). - See the [Unity demo game with the SDK installed](https://assetstore.unity.com/packages/decentralization/demo-game-dragon-crasher-with-metamask-sdk-infura-and-truffle-249789) for advanced use cases. - ::: +:::
diff --git a/wallet/concepts/smart-contracts.md b/wallet/concepts/smart-contracts.md index ac431e636ef..12b153922a7 100644 --- a/wallet/concepts/smart-contracts.md +++ b/wallet/concepts/smart-contracts.md @@ -31,7 +31,7 @@ the user to add a chain that you suggest, and switch to it using a confirmation ## Contract address Every account in Ethereum has an address, whether it's an external key-pair account or a smart contract. -For any smart contract library to communicate with your contracts, a smart contract must know the exact address. +For any smart contract library to communicate with your contracts, a smart contract must know the exact address. Read about [how to find a token contact address](https://metamask.zendesk.com/hc/en-us/articles/360059683451-How-to-view-or-add-custom-token-contract-address). diff --git a/wallet/concepts/wallet-api.md b/wallet/concepts/wallet-api.md index eb83e5f72bf..396ca662d92 100644 --- a/wallet/concepts/wallet-api.md +++ b/wallet/concepts/wallet-api.md @@ -13,7 +13,7 @@ The API methods are documented in the following references: - [Ethereum provider API reference](../reference/provider-api.md) - [JSON-RPC API reference](/wallet/reference/json-rpc-api) - ::: +::: ## Ethereum provider API @@ -63,13 +63,13 @@ Make sure to handle errors for every call to The RPC methods are divided into the following: -- [Restricted methods](#restricted-methods) - Require user consent for actions that impact assets or data (for example, initiating a transaction). +- [Restricted methods](#restricted-methods) - Require user consent for actions that impact assets or data (for example, initiating a transaction). - [Unrestricted methods](#unrestricted-methods) - Allow dapps to perform basic actions without permission (for example, retrieving a public address). ### Restricted methods -MetaMask implements permissions based on [EIP-2255](https://eips.ethereum.org/EIPS/eip-2255) to enhance security for when users interact with dapps. -This requires that dapps obtain user consent before accessing certain features. +MetaMask implements permissions based on [EIP-2255](https://eips.ethereum.org/EIPS/eip-2255) to enhance security for when users interact with dapps. +This requires that dapps obtain user consent before accessing certain features. Under the hood, permissions are plain, JSON-compatible objects, with fields that are mostly used internally by MetaMask. @@ -79,7 +79,7 @@ Restricted methods are methods that cannot be called unless you have permission The following methods are restricted: -- [`eth_accounts`](/wallet/reference/eth_accounts) - Gaining permission requires calling `wallet_requestPermissions`. +- [`eth_accounts`](/wallet/reference/eth_accounts) - Gaining permission requires calling `wallet_requestPermissions`. Granting permission for `eth_accounts` also grants permissions for the following methods: - [`eth_sendTransaction`](/wallet/reference/eth_sendTransaction) diff --git a/wallet/concepts/wallet-interoperability.md b/wallet/concepts/wallet-interoperability.md index 51d4781f715..a4e50ca4bad 100644 --- a/wallet/concepts/wallet-interoperability.md +++ b/wallet/concepts/wallet-interoperability.md @@ -11,11 +11,11 @@ mechanism to the [`window.ethereum`](wallet-api.md#ethereum-provider-api) inject This mechanism is enabled by using the standardized interfaces defined by EIP-6963. :::info Why EIP-6963? -[EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) standardizes the interface for wallet providers, +[EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) standardizes the interface for wallet providers, but it results in conflicts when users have multiple wallets installed, due to how the provider -object is injected. -This can cause issues with wallet discovery, user onboarding, and connecting. -The wallet discovery mechanism introduced by EIP-6963 solves these issues. +object is injected. +This can cause issues with wallet discovery, user onboarding, and connecting. +The wallet discovery mechanism introduced by EIP-6963 solves these issues. ::: The following is a demo of the user experience of detecting multiple wallets, showing the data @@ -62,8 +62,8 @@ interface announces an event dispatched by the wallet: ```typescript interface EIP6963AnnounceProviderEvent extends CustomEvent { - type: "eip6963:announceProvider" - detail: EIP6963ProviderDetail + type: "eip6963:announceProvider"; + detail: EIP6963ProviderDetail; } ``` @@ -72,7 +72,7 @@ interface requests an event dispatched by a dapp: ```typescript interface EIP6963RequestProviderEvent extends Event { - type: "eip6963:requestProvider" + type: "eip6963:requestProvider"; } ``` @@ -112,7 +112,7 @@ MetaMask, resolving potential conflicts that might arise with other wallet exten more stable and reliable interaction for users. The SDK is also being integrated into [Wagmi 2+](https://wagmi.sh/), which supports EIP-6963. -The SDK on its own supports connecting _only_ to MetaMask via EIP-6963, so if you intend to support +The SDK on its own supports connecting *only* to MetaMask via EIP-6963, so if you intend to support discovery of other wallets, we recommend using other methods of adding EIP-6963 support, such as Wagmi 2+. diff --git a/wallet/how-to/connect/access-accounts.md b/wallet/how-to/connect/access-accounts.md index e071a9ed516..ecacf82935e 100644 --- a/wallet/how-to/connect/access-accounts.md +++ b/wallet/how-to/connect/access-accounts.md @@ -42,12 +42,12 @@ button: // You should only attempt to request the user's account in response to user interaction, such as // selecting a button. Otherwise, you pop-up spam the user like it's 1999. If you fail to retrieve // the user's account, you should encourage the user to initiate the attempt. -const ethereumButton = document.querySelector(".enableEthereumButton") -const showAccount = document.querySelector(".showAccount") +const ethereumButton = document.querySelector(".enableEthereumButton"); +const showAccount = document.querySelector(".showAccount"); ethereumButton.addEventListener("click", () => { - getAccount() -}) + getAccount(); +}); // While awaiting the call to eth_requestAccounts, you should disable any buttons the user can // select to initiate the request. MetaMask rejects any additional requests while the first is still @@ -55,17 +55,17 @@ ethereumButton.addEventListener("click", () => { async function getAccount() { const accounts = await provider // Or window.ethereum if you don't support EIP-6963. .request({ method: "eth_requestAccounts" }) - .catch((err) => { - if (err.code === 4001) { - // EIP-1193 userRejectedRequest error. - // If this happens, the user rejected the connection request. - console.log("Please connect to MetaMask.") - } else { - console.error(err) - } - }) - const account = accounts[0] - showAccount.innerHTML = account + .catch((err) => { + if (err.code === 4001) { + // EIP-1193 userRejectedRequest error. + // If this happens, the user rejected the connection request. + console.log("Please connect to MetaMask."); + } else { + console.error(err); + } + }); + const account = accounts[0]; + showAccount.innerHTML = account; } ``` @@ -87,7 +87,7 @@ be notified when the user changes accounts. The following code handles user accounts and detects when the user changes accounts: ```javascript title="index.js" -let currentAccount = null +let currentAccount = null; provider // Or window.ethereum if you don't support EIP-6963. .request({ method: "eth_accounts" }) .then(handleAccountsChanged) @@ -95,24 +95,24 @@ provider // Or window.ethereum if you don't support EIP-6963. // Some unexpected error. // For backwards compatibility reasons, if no accounts are available, eth_accounts returns an // empty array. - console.error(err) - }) + console.error(err); + }); // Note that this event is emitted on page load. If the array of accounts is non-empty, you're // already connected. provider // Or window.ethereum if you don't support EIP-6963. - .on("accountsChanged", handleAccountsChanged) + .on("accountsChanged", handleAccountsChanged); // eth_accounts always returns an array. function handleAccountsChanged(accounts) { if (accounts.length === 0) { // MetaMask is locked or the user has not connected any accounts. - console.log("Please connect to MetaMask.") + console.log("Please connect to MetaMask."); } else if (accounts[0] !== currentAccount) { // Reload your interface with accounts[0]. - currentAccount = accounts[0] + currentAccount = accounts[0]; // Update the account displayed (see the HTML for the connect button) - showAccount.innerHTML = currentAccount + showAccount.innerHTML = currentAccount; } } ``` diff --git a/wallet/how-to/connect/index.md b/wallet/how-to/connect/index.md index 93f555dcca4..078d4355525 100644 --- a/wallet/how-to/connect/index.md +++ b/wallet/how-to/connect/index.md @@ -17,7 +17,7 @@ Learn more about EIP-6963 in [Wallet interoperability](../../concepts/wallet-int ::: :::tip -To connect to MetaMask without using EIP-6963, see the [Create a simple dapp](../../tutorials/javascript-dapp-simple.md) tutorial. +To connect to MetaMask without using EIP-6963, see the [Create a simple dapp](../../tutorials/javascript-dapp-simple.md) tutorial. ::: You can connect to MetaMask [using third-party libraries](#connect-to-metamask-using-third-party-libraries) @@ -74,8 +74,8 @@ interface EIP6963ProviderDetail { type EIP6963AnnounceProviderEvent = { detail: { - info: EIP6963ProviderInfo - provider: Readonly + info: EIP6963ProviderInfo, + provider: Readonly, } } @@ -83,18 +83,9 @@ interface EIP1193Provider { isStatus?: boolean host?: string path?: string - sendAsync?: ( - request: { method: string; params?: Array }, - callback: (error: Error | null, response: unknown) => void - ) => void - send?: ( - request: { method: string; params?: Array }, - callback: (error: Error | null, response: unknown) => void - ) => void - request: (request: { - method: string - params?: Array - }) => Promise + sendAsync?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + send?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + request: (request: { method: string, params?: Array }) => Promise } ``` @@ -113,7 +104,7 @@ Update `src/main.ts` with the following code: import "./style.css" import { listProviders } from "./providers.ts" -document.querySelector("#app")!.innerHTML = ` +document.querySelector('#app')!.innerHTML = `
@@ -142,11 +133,10 @@ declare global { } // Connect to the selected provider using eth_requestAccounts. -const connectWithProvider = async ( - wallet: EIP6963AnnounceProviderEvent["detail"] -) => { +const connectWithProvider = async (wallet: EIP6963AnnounceProviderEvent["detail"]) => { try { - await wallet.provider.request({ method: "eth_requestAccounts" }) + await wallet.provider + .request({ method: "eth_requestAccounts" }) } catch (error) { console.error("Failed to connect to provider:", error) } @@ -154,16 +144,15 @@ const connectWithProvider = async ( // Display detected providers as connect buttons. export function listProviders(element: HTMLDivElement) { - window.addEventListener( - "eip6963:announceProvider", + window.addEventListener("eip6963:announceProvider", (event: EIP6963AnnounceProviderEvent) => { const button = document.createElement("button") - + button.innerHTML = ` ${event.detail.info.name}
${event.detail.info.name}
` - + // Call connectWithProvider when a user selects the button. button.onclick = () => connectWithProvider(event.detail) element.appendChild(button) @@ -231,8 +220,8 @@ interface EIP6963ProviderDetail { type EIP6963AnnounceProviderEvent = { detail: { - info: EIP6963ProviderInfo - provider: Readonly + info: EIP6963ProviderInfo, + provider: Readonly, } } @@ -240,18 +229,9 @@ interface EIP1193Provider { isStatus?: boolean host?: string path?: string - sendAsync?: ( - request: { method: string; params?: Array }, - callback: (error: Error | null, response: unknown) => void - ) => void - send?: ( - request: { method: string; params?: Array }, - callback: (error: Error | null, response: unknown) => void - ) => void - request: (request: { - method: string - params?: Array - }) => Promise + sendAsync?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + send?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + request: (request: { method: string, params?: Array }) => Promise } ``` @@ -300,7 +280,7 @@ export const DiscoverWalletProviders = () => { // Connect to the selected provider using eth_requestAccounts. const handleConnect = async (providerWithInfo: EIP6963ProviderDetail) => { try { - const accounts = await providerWithInfo.provider.request({ + const accounts = await providerWithInfo.provider.request({ method: "eth_requestAccounts" }) @@ -349,7 +329,7 @@ In this code: - `selectedWallet` is a state variable that holds the user's most recently selected wallet. - `userAccount` is a state variable that holds the user's connected wallet's address. - `useSyncProviders` is a custom hook that returns the providers array (wallets installed in the browser). - + The `handleConnect` function takes a `providerWithInfo`, which is an `EIP6963ProviderDetail` object. That object is used to request the user's accounts from the provider using [`eth_requestAccounts`](/wallet/reference/eth_requestaccounts). @@ -376,25 +356,23 @@ declare global { let providers: EIP6963ProviderDetail[] = [] export const store = { - value: () => providers, - subscribe: (callback: () => void) => { - function onAnnouncement(event: EIP6963AnnounceProviderEvent) { - if (providers.map((p) => p.info.uuid).includes(event.detail.info.uuid)) - return + value: ()=> providers, + subscribe: (callback: ()=> void) => { + function onAnnouncement(event: EIP6963AnnounceProviderEvent){ + if(providers.map(p => p.info.uuid).includes(event.detail.info.uuid)) return providers = [...providers, event.detail] callback() } // Listen for eip6963:announceProvider and call onAnnouncement when the event is triggered. window.addEventListener("eip6963:announceProvider", onAnnouncement) - + // Dispatch the event, which triggers the event listener in the MetaMask wallet. window.dispatchEvent(new Event("eip6963:requestProvider")) - + // Return a function that removes the event listern. - return () => - window.removeEventListener("eip6963:announceProvider", onAnnouncement) - }, + return () => window.removeEventListener("eip6963:announceProvider", onAnnouncement) + } } ``` @@ -404,8 +382,7 @@ Also, add a file `useSyncProviders.ts` with the following code to the `hooks` di import { useSyncExternalStore } from "react" import { store } from "./store" -export const useSyncProviders = () => - useSyncExternalStore(store.subscribe, store.value, store.value) +export const useSyncProviders = ()=> useSyncExternalStore(store.subscribe, store.value, store.value) ``` This hook allows you to subscribe to MetaMask events, read updated values, and update components. @@ -427,7 +404,7 @@ export const formatChainAsNum = (chainIdHex: string) => { } export const formatAddress = (addr: string) => { - const upperAfterLastTwo = addr.slice(0, 2) + addr.slice(2) + const upperAfterLastTwo = addr.slice(0,2) + addr.slice(2) return `${upperAfterLastTwo.substring(0, 5)}...${upperAfterLastTwo.substring(39)}` } ``` diff --git a/wallet/how-to/display/tokens.md b/wallet/how-to/display/tokens.md index 372cc22a2bc..2fc29aae741 100644 --- a/wallet/how-to/display/tokens.md +++ b/wallet/how-to/display/tokens.md @@ -39,10 +39,10 @@ extension (not on mobile). To prompt users to add an ERC-20 token, you can add something like the following to your project script: ```javascript -const tokenAddress = "0xd00981105e61274c8a5cd5a88fe7e037d935b513" -const tokenSymbol = "TUT" -const tokenDecimals = 18 -const tokenImage = "http://placekitten.com/200/300" +const tokenAddress = "0xd00981105e61274c8a5cd5a88fe7e037d935b513"; +const tokenSymbol = "TUT"; +const tokenDecimals = 18; +const tokenImage = "http://placekitten.com/200/300"; try { // 'wasAdded' is a boolean. Like any RPC method, an error can be thrown. @@ -62,15 +62,15 @@ try { image: tokenImage, }, }, - }) + }); if (wasAdded) { - console.log("Thanks for your interest!") + console.log("Thanks for your interest!"); } else { - console.log("Your loss!") + console.log("Your loss!"); } } catch (error) { - console.log(error) + console.log(error); } ``` @@ -128,15 +128,15 @@ try { tokenId: "1", }, }, - }) + }); if (wasAdded) { - console.log("User successfully added the token!") + console.log("User successfully added the token!"); } else { - console.log("User did not add the token.") + console.log("User did not add the token."); } } catch (error) { - console.log(error) + console.log(error); } ``` diff --git a/wallet/how-to/manage-networks/add-network.md b/wallet/how-to/manage-networks/add-network.md index 06daa7b7349..fc364023aa1 100644 --- a/wallet/how-to/manage-networks/add-network.md +++ b/wallet/how-to/manage-networks/add-network.md @@ -47,7 +47,7 @@ try { .request({ method: "wallet_switchEthereumChain", params: [{ chainId: "0xf00" }], - }) + }); } catch (switchError) { // This error code indicates that the chain has not been added to MetaMask. if (switchError.code === 4902) { @@ -62,7 +62,7 @@ try { rpcUrls: ["https://..."] /* ... */, }, ], - }) + }); } catch (addError) { // Handle "add" error. } diff --git a/wallet/how-to/manage-networks/detect-network.md b/wallet/how-to/manage-networks/detect-network.md index 03873a7e896..c60f6a4a448 100644 --- a/wallet/how-to/manage-networks/detect-network.md +++ b/wallet/how-to/manage-networks/detect-network.md @@ -17,13 +17,13 @@ For example, the following code detects a user's network and when the user chang ```javascript title="index.js" const chainId = await provider // Or window.ethereum if you don't support EIP-6963. - .request({ method: "eth_chainId" }) + .request({ method: "eth_chainId" }); provider // Or window.ethereum if you don't support EIP-6963. - .on("chainChanged", handleChainChanged) + .on("chainChanged", handleChainChanged); function handleChainChanged(chainId) { // We recommend reloading the page, unless you must do otherwise. - window.location.reload() + window.location.reload(); } ``` diff --git a/wallet/how-to/manage-permissions.md b/wallet/how-to/manage-permissions.md index e962c89851c..318281f7d22 100644 --- a/wallet/how-to/manage-permissions.md +++ b/wallet/how-to/manage-permissions.md @@ -31,9 +31,9 @@ the restricted method [`eth_accounts`](/wallet/reference/eth_accounts): :::info note To access accounts, we recommend using [`eth_requestAccounts`](/wallet/reference/eth_requestAccounts), which automatically asks for permission to use `eth_accounts` by calling `wallet_requestPermissions` -internally. +internally. See [how to access a user's accounts](../connect/access-accounts) for more information. -Granting permission for `eth_accounts` also grants access to [`eth_sendTransaction`](/wallet/reference/eth_sendTransaction), [`personal_sign`](/wallet/reference/personal_sign), and [`eth_signTypedData_v4`](/wallet/reference/eth_signTypedData_v4). +Granting permission for `eth_accounts` also grants access to [`eth_sendTransaction`](/wallet/reference/eth_sendTransaction), [`personal_sign`](/wallet/reference/personal_sign), and [`eth_signTypedData_v4`](/wallet/reference/eth_signTypedData_v4). ::: ## Request permissions example @@ -41,7 +41,7 @@ Granting permission for `eth_accounts` also grants access to [`eth_sendTransacti The following example uses `wallet_requestPermissions` to request permission from the user to call `eth_accounts`: ```javascript -document.getElementById("requestPermissionsButton", requestPermissions) +document.getElementById("requestPermissionsButton", requestPermissions); function requestPermissions() { provider // Or window.ethereum if you don't support EIP-6963. @@ -52,19 +52,19 @@ function requestPermissions() { .then((permissions) => { const accountsPermission = permissions.find( (permission) => permission.parentCapability === "eth_accounts" - ) + ); if (accountsPermission) { - console.log("eth_accounts permission successfully requested!") + console.log("eth_accounts permission successfully requested!"); } }) .catch((error) => { if (error.code === 4001) { // EIP-1193 userRejectedRequest error - console.log("Permissions needed to continue.") + console.log("Permissions needed to continue."); } else { - console.error(error) + console.error(error); } - }) + }); } ``` @@ -81,5 +81,5 @@ await provider // Or window.ethereum if you don't support EIP-6963. eth_accounts: {}, }, ], - }) -``` + }); +``` \ No newline at end of file diff --git a/wallet/how-to/onboard-users.md b/wallet/how-to/onboard-users.md index c89b227073a..264618b421d 100644 --- a/wallet/how-to/onboard-users.md +++ b/wallet/how-to/onboard-users.md @@ -4,8 +4,8 @@ description: Simplify the MetaMask onboarding experience for your users. sidebar_position: 8 --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Use the MetaMask onboarding library @@ -32,30 +32,30 @@ You don't need to set up the onboarding library if you use the SDK. 1. Install [@metamask/onboarding](https://github.com/MetaMask/metamask-onboarding). 1. Import the library or include it in your page: - ```javascript - // As an ES6 module - import MetaMaskOnboarding from "@metamask/onboarding" - // Or as an ES5 module - const MetaMaskOnboarding = require("@metamask/onboarding") - ``` + ```javascript + // As an ES6 module + import MetaMaskOnboarding from "@metamask/onboarding"; + // Or as an ES5 module + const MetaMaskOnboarding = require("@metamask/onboarding"); + ``` - Alternatively, you can include the prebuilt ES5 bundle that ships with the library: + Alternatively, you can include the prebuilt ES5 bundle that ships with the library: - ```html - - ``` + ```html + + ``` 1. Create a new instance of the onboarding library: - ```javascript - const onboarding = new MetaMaskOnboarding() - ``` + ```javascript + const onboarding = new MetaMaskOnboarding(); + ``` 1. Start the onboarding process in response to a user event (for example, a button click): - ```javascript - onboarding.startOnboarding() - ``` + ```javascript + onboarding.startOnboarding(); + ``` ## Example @@ -65,69 +65,72 @@ The following are example ways to use the onboarding library in various framewor ```jsx -import MetaMaskOnboarding from "@metamask/onboarding" -import React from "react" +import MetaMaskOnboarding from "@metamask/onboarding"; +import React from "react"; -const ONBOARD_TEXT = "Click here to install MetaMask!" -const CONNECT_TEXT = "Connect" -const CONNECTED_TEXT = "Connected" +const ONBOARD_TEXT = "Click here to install MetaMask!"; +const CONNECT_TEXT = "Connect"; +const CONNECTED_TEXT = "Connected"; export function OnboardingButton() { - const [buttonText, setButtonText] = React.useState(ONBOARD_TEXT) - const [isDisabled, setDisabled] = React.useState(false) - const [accounts, setAccounts] = React.useState([]) - const onboarding = React.useRef() + const [buttonText, setButtonText] = React.useState(ONBOARD_TEXT); + const [isDisabled, setDisabled] = React.useState(false); + const [accounts, setAccounts] = React.useState([]); + const onboarding = React.useRef(); React.useEffect(() => { if (!onboarding.current) { - onboarding.current = new MetaMaskOnboarding() + onboarding.current = new MetaMaskOnboarding(); } - }, []) + }, []); React.useEffect(() => { if (MetaMaskOnboarding.isMetaMaskInstalled()) { if (accounts.length > 0) { - setButtonText(CONNECTED_TEXT) - setDisabled(true) - onboarding.current.stopOnboarding() + setButtonText(CONNECTED_TEXT); + setDisabled(true); + onboarding.current.stopOnboarding(); } else { - setButtonText(CONNECT_TEXT) - setDisabled(false) + setButtonText(CONNECT_TEXT); + setDisabled(false); } } - }, [accounts]) + }, [accounts]); React.useEffect(() => { function handleNewAccounts(newAccounts) { - setAccounts(newAccounts) + setAccounts(newAccounts); } if (MetaMaskOnboarding.isMetaMaskInstalled()) { provider // Or window.ethereum if you don't support EIP-6963. .request({ method: "eth_requestAccounts" }) - .then(handleNewAccounts) + .then(handleNewAccounts); provider // Or window.ethereum if you don't support EIP-6963. - .on("accountsChanged", handleNewAccounts) + .on("accountsChanged", handleNewAccounts); return () => { provider // Or window.ethereum if you don't support EIP-6963. - .removeListener("accountsChanged", handleNewAccounts) - } + .removeListener( + "accountsChanged", + handleNewAccounts + ); + }; } - }, []) + }, []); const onClick = () => { if (MetaMaskOnboarding.isMetaMaskInstalled()) { provider // Or window.ethereum if you don't support EIP-6963. .request({ method: "eth_requestAccounts" }) - .then((newAccounts) => setAccounts(newAccounts)) + .then((newAccounts) => setAccounts(newAccounts)); } else { - onboarding.current.startOnboarding() + onboarding.current.startOnboarding(); } - } + }; return ( - ) + ); } ``` @@ -153,54 +156,55 @@ helpful documentation: ```html - - MetaMask Onboarding Example - - - -

Sample Dapp

- - - - + + MetaMask Onboarding Example + + + +

Sample Dapp

+ + + + ``` diff --git a/wallet/how-to/run-devnet.md b/wallet/how-to/run-devnet.md index 23ff9301665..e6d1e54c5fa 100644 --- a/wallet/how-to/run-devnet.md +++ b/wallet/how-to/run-devnet.md @@ -21,56 +21,56 @@ Follow these steps to connect MetaMask to Hardhat Network. 1. [Set up a Hardhat project.](https://hardhat.org/hardhat-runner/docs/guides/project-setup) 2. Create a new - [MetaMask seed phrase]() - specifically for development. - - :::caution important - Your seed phrase controls all your accounts, so we recommend keeping at least one seed phrase for - development, separate from any used to store real value. - You can manage multiple seed phrases by using multiple browser profiles, each with its own - MetaMask installation. - ::: + [MetaMask seed phrase](https://support.metamask.io/hc/en-us/articles/360060826432-What-is-a-Secret-Recovery-Phrase-and-how-to-keep-your-crypto-wallet-secure#:~:text=Your%20Secret%20Recovery%20Phrase%20(SRP,are%20connected%20to%20that%20phrase.)) + specifically for development. + + :::caution important + Your seed phrase controls all your accounts, so we recommend keeping at least one seed phrase for + development, separate from any used to store real value. + You can manage multiple seed phrases by using multiple browser profiles, each with its own + MetaMask installation. + ::: 3. In your `hardhat.config.js` file, specify a - [`networks` configuration](https://hardhat.org/hardhat-runner/docs/config#networks-configuration) - with a `hardhat` network. - In this `networks.hardhat` configuration: - - - Specify your MetaMask seed phrase in the - [`accounts.mnemonic`](https://hardhat.org/hardhat-network/docs/reference#accounts) field. - - :::tip - Alternatively, to prevent committing your seed phrase, we recommend adding your seed phrase to a - [`.env` file](https://docs.infura.io/tutorials/developer-tools/javascript-dotenv) and using the - `process.env` global variable in `hardhat.config.js`. - ::: - - - Specify the [chain ID `1337`](https://hardhat.org/hardhat-network/docs/metamask-issue) in the - [`chainId`](https://hardhat.org/hardhat-network/docs/reference#chainid) field. - - For example: - - ```js title="hardhat.config.js" - module.exports = { - networks: { - hardhat: { - accounts: { - mnemonic: process.env.SEED_PHRASE, - }, - chainId: 1337, - }, - }, - } - ``` - - Hardhat automatically gives each of your first 20 accounts 10000 test ether (you can modify - these numbers in the [`accounts`](https://hardhat.org/hardhat-network/docs/reference#accounts) - configuration), which makes it easy to start development. + [`networks` configuration](https://hardhat.org/hardhat-runner/docs/config#networks-configuration) + with a `hardhat` network. + In this `networks.hardhat` configuration: + + - Specify your MetaMask seed phrase in the + [`accounts.mnemonic`](https://hardhat.org/hardhat-network/docs/reference#accounts) field. + + :::tip + Alternatively, to prevent committing your seed phrase, we recommend adding your seed phrase to a + [`.env` file](https://docs.infura.io/tutorials/developer-tools/javascript-dotenv) and using the + `process.env` global variable in `hardhat.config.js`. + ::: + + - Specify the [chain ID `1337`](https://hardhat.org/hardhat-network/docs/metamask-issue) in the + [`chainId`](https://hardhat.org/hardhat-network/docs/reference#chainid) field. + + For example: + + ```js title="hardhat.config.js" + module.exports = { + networks: { + hardhat: { + accounts: { + mnemonic: process.env.SEED_PHRASE, + }, + chainId: 1337, + }, + }, + }; + ``` + + Hardhat automatically gives each of your first 20 accounts 10000 test ether (you can modify + these numbers in the [`accounts`](https://hardhat.org/hardhat-network/docs/reference#accounts) + configuration), which makes it easy to start development. 4. Run `npx hardhat node` to run Hardhat Network and expose a JSON-RPC interface. 5. You can now connect MetaMask to your Hardhat Network RPC URL, `http://127.0.0.1:8545/`. - In the MetaMask extension: + In the MetaMask extension: 1. In the upper left corner, select the network you're currently connected to. @@ -92,7 +92,7 @@ Follow these steps to connect MetaMask to Hardhat Network. If you restart your development network, you can accidentally confuse MetaMask because it calculates the next [nonce](send-transactions.md#nonce) based on both the -network state _and_ the known sent transactions. +network state *and* the known sent transactions. To clear MetaMask's transaction queue and reset its nonce calculation, go to **Settings > Advanced** and select **Reset account**. diff --git a/wallet/how-to/secure-dapp.md b/wallet/how-to/secure-dapp.md index a1f403b6807..004c6e2674b 100644 --- a/wallet/how-to/secure-dapp.md +++ b/wallet/how-to/secure-dapp.md @@ -48,9 +48,9 @@ app.use((req, res, next) => { res.setHeader( "Content-Security-Policy", "default-src 'self'; frame-ancestors 'none'" - ) - next() -}) + ); + next(); +}); ``` In a header, this looks like the following: diff --git a/wallet/how-to/sign-data/index.md b/wallet/how-to/sign-data/index.md index 1e6cb7233ce..0cdf13aeea3 100644 --- a/wallet/how-to/sign-data/index.md +++ b/wallet/how-to/sign-data/index.md @@ -64,7 +64,7 @@ The following is an example of using `eth_signTypedData_v4` with MetaMask: ```javascript title="index.js" signTypedDataV4Button.addEventListener("click", async function (event) { - event.preventDefault() + event.preventDefault(); // eth_signTypedData_v4 parameters. All of these parameters affect the resulting signature. const msgParams = JSON.stringify({ @@ -130,12 +130,12 @@ signTypedDataV4Button.addEventListener("click", async function (event) { { name: "wallets", type: "address[]" }, ], }, - }) + }); - var from = await web3.eth.getAccounts() + var from = await web3.eth.getAccounts(); - var params = [from[0], msgParams] - var method = "eth_signTypedData_v4" + var params = [from[0], msgParams]; + var method = "eth_signTypedData_v4"; provider // Or window.ethereum if you don't support EIP-6963. .sendAsync( @@ -145,31 +145,26 @@ signTypedDataV4Button.addEventListener("click", async function (event) { from: from[0], }, function (err, result) { - if (err) return console.dir(err) + if (err) return console.dir(err); if (result.error) { - alert(result.error.message) + alert(result.error.message); } - if (result.error) return console.error("ERROR", result) - console.log("TYPED SIGNED:" + JSON.stringify(result.result)) + if (result.error) return console.error("ERROR", result); + console.log("TYPED SIGNED:" + JSON.stringify(result.result)); const recovered = sigUtil.recoverTypedSignature_v4({ data: JSON.parse(msgParams), sig: result.result, - }) + }); - if ( - ethUtil.toChecksumAddress(recovered) === - ethUtil.toChecksumAddress(from) - ) { - alert("Successfully recovered signer as " + from) + if (ethUtil.toChecksumAddress(recovered) === ethUtil.toChecksumAddress(from)) { + alert("Successfully recovered signer as " + from); } else { - alert( - "Failed to verify signer when comparing " + result + " to " + from - ) + alert("Failed to verify signer when comparing " + result + " to " + from); } } - ) -}) + ); +}); ``` The following HTML displays a sign button: @@ -201,14 +196,13 @@ Because MetaMask supports existing applications, MetaMask implements both `perso You might need to check what method your supported signers use for a given implementation. :::caution important - - Don't use this method to display binary data, because the user wouldn't be able to understand what they're agreeing to. - If using this method for a signature challenge, think about what would prevent a phisher from reusing the same challenge and impersonating your site. Add text referring to your domain, or the current time, so the user can easily verify if this challenge is legitimate. - ::: +::: ### Example @@ -216,24 +210,24 @@ The following is an example of using `personal_sign` with MetaMask: ```javascript title="index.js" personalSignButton.addEventListener("click", async function (event) { - event.preventDefault() - const exampleMessage = "Example `personal_sign` message." + event.preventDefault(); + const exampleMessage = "Example `personal_sign` message."; try { - const from = accounts[0] + const from = accounts[0]; // For historical reasons, you must submit the message to sign in hex-encoded UTF-8. // This uses a Node.js-style buffer shim in the browser. - const msg = `0x${Buffer.from(exampleMessage, "utf8").toString("hex")}` + const msg = `0x${Buffer.from(exampleMessage, "utf8").toString("hex")}`; const sign = await ethereum.request({ method: "personal_sign", params: [msg, from], - }) - personalSignResult.innerHTML = sign - personalSignVerify.disabled = false + }); + personalSignResult.innerHTML = sign; + personalSignVerify.disabled = false; } catch (err) { - console.error(err) - personalSign.innerHTML = `Error: ${err.message}` + console.error(err); + personalSign.innerHTML = `Error: ${err.message}`; } -}) +}); ``` The following HTML displays a sign button: diff --git a/wallet/how-to/sign-data/siwe.md b/wallet/how-to/sign-data/siwe.md index 2d424140af6..9ecec3b0a2a 100644 --- a/wallet/how-to/sign-data/siwe.md +++ b/wallet/how-to/sign-data/siwe.md @@ -47,26 +47,26 @@ The following is an example of setting up SIWE with MetaMask using ```javascript title="index.js" const siweSign = async (siweMessage) => { try { - const from = accounts[0] - const msg = `0x${Buffer.from(siweMessage, "utf8").toString("hex")}` + const from = accounts[0]; + const msg = `0x${Buffer.from(siweMessage, "utf8").toString("hex")}`; const sign = await provider // Or window.ethereum if you don't support EIP-6963. .request({ method: "personal_sign", params: [msg, from], - }) - siweResult.innerHTML = sign + }); + siweResult.innerHTML = sign; } catch (err) { - console.error(err) - siweResult.innerHTML = `Error: ${err.message}` + console.error(err); + siweResult.innerHTML = `Error: ${err.message}`; } -} +}; siwe.onclick = async () => { - const domain = window.location.host - const from = accounts[0] - const siweMessage = `${domain} wants you to sign in with your Ethereum account:\n${from}\n\nI accept the MetaMask Terms of Service: https://community.metamask.io/tos\n\nURI: https://${domain}\nVersion: 1\nChain ID: 1\nNonce: 32891757\nIssued At: 2021-09-30T16:25:24.000Z` - siweSign(siweMessage) -} + const domain = window.location.host; + const from = accounts[0]; + const siweMessage = `${domain} wants you to sign in with your Ethereum account:\n${from}\n\nI accept the MetaMask Terms of Service: https://community.metamask.io/tos\n\nURI: https://${domain}\nVersion: 1\nChain ID: 1\nNonce: 32891757\nIssued At: 2021-09-30T16:25:24.000Z`; + siweSign(siweMessage); +}; ``` The following HTML displays the SIWE button: diff --git a/wallet/how-to/use-sdk/3rd-party-libraries/wagmi.md b/wallet/how-to/use-sdk/3rd-party-libraries/wagmi.md index 9446a81a5de..f171122a71e 100644 --- a/wallet/how-to/use-sdk/3rd-party-libraries/wagmi.md +++ b/wallet/how-to/use-sdk/3rd-party-libraries/wagmi.md @@ -34,7 +34,7 @@ const MetaMaskOptions = { }, infuraAPIKey: "YOUR-API-KEY", // Other options. -} +}; ``` #### Dapp metadata @@ -63,9 +63,9 @@ Use the `MetaMaskOptions` you created in the previous step when adding the `meta For example: ```javascript -import { createConfig, http } from "wagmi" -import { mainnet, sepolia } from "wagmi/chains" -import { metaMask } from "wagmi/connectors" +import { createConfig, http } from "wagmi"; +import { mainnet, sepolia } from "wagmi/chains"; +import { metaMask } from "wagmi/connectors"; const MetaMaskOptions = { dappMetadata: { @@ -73,7 +73,7 @@ const MetaMaskOptions = { }, infuraAPIKey: "YOUR-API-KEY", // Other options. -} +}; export const config = createConfig({ chains: [mainnet, sepolia], @@ -85,7 +85,7 @@ export const config = createConfig({ [mainnet.id]: http(), [sepolia.id]: http(), }, -}) +}); ``` ### 3. Implement contract interaction using `usePrepareContractWrite` @@ -97,18 +97,18 @@ This approach ensures smooth transactions by preparing the contract write operat actual execution. ```javascript -import { usePrepareContractWrite, useContractWrite } from "wagmi" +import { usePrepareContractWrite, useContractWrite } from "wagmi"; const { config } = usePrepareContractWrite({ address: "0xContractAddress", abi: contractABI, functionName: "functionToCall", args: [arg1, arg2], -}) +}); -const { write } = useContractWrite(config) +const { write } = useContractWrite(config); -write() +write(); ``` ## Benefits of using the Infura API with Wagmi diff --git a/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard.md b/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard.md index fec5a61065c..8e9ab797577 100644 --- a/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard.md +++ b/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard.md @@ -36,7 +36,7 @@ npm i @web3-onboard/metamask In your project script, add the following to import the module: ```javascript -import metamaskSDK from "@web3-onboard/metamask" +import metamaskSDK from "@web3-onboard/metamask"; ``` ### 3. Instantiate the module @@ -52,7 +52,7 @@ const metamaskSDKWallet = metamaskSDK({ name: "Example Web3-Onboard Dapp", }, }, -}) +}); ``` ### 4. Use the module @@ -66,10 +66,10 @@ const onboard = Onboard({ metamaskSDKWallet, // Other wallets. ], -}) +}); -const connectedWallets = await onboard.connectWallet() -console.log(connectedWallets) +const connectedWallets = await onboard.connectWallet(); +console.log(connectedWallets); ``` ## Example diff --git a/wallet/how-to/use-sdk/gaming/unity/connect-and-sign.md b/wallet/how-to/use-sdk/gaming/unity/connect-and-sign.md index e2e5633abcb..7af278f9165 100644 --- a/wallet/how-to/use-sdk/gaming/unity/connect-and-sign.md +++ b/wallet/how-to/use-sdk/gaming/unity/connect-and-sign.md @@ -23,28 +23,28 @@ You can [connect and sign](../../javascript/connect-and-sign.md) in a single int 2. In your script, create a new function named `ConnectAndSign`: - ```csharp - public void ConnectAndSign() - { - MetaMaskUnity.Instance.ConnectAndSign("This is a test message"); - } - ``` - - Replace the test message with any string message you want to sign. - - :::caution important - Make sure you initialize [`MetaMaskUnity.Instance`](../../../../reference/sdk-unity-api.md#instance) - before using this function. - To do so, enable **Initialize On Awake** in the **MetaMask Unity** script inspector, or run - [`MetaMask.Instance.Initialize()`](../../../../reference/sdk-unity-api.md#initialize). - ::: + ```csharp + public void ConnectAndSign() + { + MetaMaskUnity.Instance.ConnectAndSign("This is a test message"); + } + ``` + + Replace the test message with any string message you want to sign. + + :::caution important + Make sure you initialize [`MetaMaskUnity.Instance`](../../../../reference/sdk-unity-api.md#instance) + before using this function. + To do so, enable **Initialize On Awake** in the **MetaMask Unity** script inspector, or run + [`MetaMask.Instance.Initialize()`](../../../../reference/sdk-unity-api.md#initialize). + ::: 3. Call the `ConnectAndSign` function whenever you want to establish a connection and sign a message. - For example, you can call this function when a button is clicked: - - ```csharp - public void OnButtonClick() - { - ConnectAndSign(); - } - ``` + For example, you can call this function when a button is clicked: + + ```csharp + public void OnButtonClick() + { + ConnectAndSign(); + } + ``` diff --git a/wallet/how-to/use-sdk/gaming/unity/dweb.md b/wallet/how-to/use-sdk/gaming/unity/dweb.md index 2f95a91c9dd..6da71a62ab9 100644 --- a/wallet/how-to/use-sdk/gaming/unity/dweb.md +++ b/wallet/how-to/use-sdk/gaming/unity/dweb.md @@ -6,8 +6,8 @@ tags: - Unity SDK --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Enable human-readable addresses in Unity diff --git a/wallet/how-to/use-sdk/gaming/unity/index.md b/wallet/how-to/use-sdk/gaming/unity/index.md index 105ab1b2774..e1983502793 100644 --- a/wallet/how-to/use-sdk/gaming/unity/index.md +++ b/wallet/how-to/use-sdk/gaming/unity/index.md @@ -62,7 +62,7 @@ If you don't have TextMeshPro installed, the Unity editor automatically prompts

| File or directory | Contents | -| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | +|--------------------------|----------------------------------------------------------------------------------------------------------------------------------| | `Documentation` | Documentation and link to online documentation | | `Editor` | Editor-only code such as Setup GUI windows, data persistence for SDK settings | | `Plugins` | Plugins needed by the package (the ECIES Platform runtime libraries and core SDK Codebase) | @@ -71,6 +71,7 @@ If you don't have TextMeshPro installed, the Unity editor automatically prompts | `LICENSE.md` | Package license | | `Third Party Notices.md` | Third party notices | +

@@ -90,9 +91,9 @@ You first must initialize by doing one of the following: - Manually call `Initialize()`: - ```csharp - MetaMaskUnity.Instance.Initialize(); - ``` + ```csharp + MetaMaskUnity.Instance.Initialize(); + ``` - Check **Initialize On Start** on the component within the editor. @@ -206,7 +207,7 @@ To update the SDK to the latest version available on the Unity Asset Store: 1. Update and import the latest package using the Unity Package Manager. 2. Go to **Tools > MetaMask > Install in Unity**. 3. Select the **Already Installed** button. - This updates the SDK in your project. + This updates the SDK in your project. Alternatively, you can delete the existing MetaMask folder in your project and re-import it from the Package Manager or Asset Store. diff --git a/wallet/how-to/use-sdk/gaming/unity/infura.md b/wallet/how-to/use-sdk/gaming/unity/infura.md index f6ad72663a6..0742aa7c839 100644 --- a/wallet/how-to/use-sdk/gaming/unity/infura.md +++ b/wallet/how-to/use-sdk/gaming/unity/infura.md @@ -37,13 +37,13 @@ your Unity game. 1. Open your Unity project with the SDK installed. 2. Navigate to the game object in your scene (or the Prefab instance) that currently stores the - `MetaMask Unity` script. - In the `Demo` scene, this is the `MetaMaskUnitySDK` game object. + `MetaMask Unity` script. + In the `Demo` scene, this is the `MetaMaskUnitySDK` game object. -3. Select the `MetaMaskUnitySDK` Prefab to view its properties in the **Inspector** window. +3. Select the `MetaMaskUnitySDK` Prefab to view its properties in the **Inspector** window. 4. In the **MetaMask Unity (Script)** section, enter your Infura API key into the **Infura Project - Id** field. + Id** field.

@@ -52,4 +52,4 @@ your Unity game.

5. Save your changes. - This automatically configures all RPC URLs that Infura supports. + This automatically configures all RPC URLs that Infura supports. diff --git a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-interface.md b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-interface.md index 2a7dc02c2a7..9cd9eaf27bc 100644 --- a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-interface.md +++ b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-interface.md @@ -19,10 +19,10 @@ To manually create a new contract interface, define a new interface that inherit Optionally, declare the [`BackedType` attribute](contract-factory.md#backed-type-contract-factory). ```csharp -#if UNITY_EDITOR || !ENABLE_MONO -[BackedType(typeof(ERC20Backing))] -#endif -public interface ERC20 : IContract +#if UNITY_EDITOR || !ENABLE_MONO +[BackedType(typeof(ERC20Backing))] +#endif +public interface ERC20 : IContract { // Declare functions. } @@ -34,10 +34,10 @@ To declare a `view` or `pure` function of the contract, first set the return typ (may differ from the actual name), and all parameters the function takes in a Task: ```csharp -#if UNITY_EDITOR || !ENABLE_MONO -[BackedType(typeof(ERC20Backing))] -#endif -public interface ERC20 : IContract +#if UNITY_EDITOR || !ENABLE_MONO +[BackedType(typeof(ERC20Backing))] +#endif +public interface ERC20 : IContract { Task BalanceOf(EvmAddress account); } @@ -48,10 +48,10 @@ declare the metadata about the contract function. This includes the `Name` and whether it's a `View` function: ```csharp -#if UNITY_EDITOR || !ENABLE_MONO -[BackedType(typeof(ERC20Backing))] -#endif -public interface ERC20 : IContract +#if UNITY_EDITOR || !ENABLE_MONO +[BackedType(typeof(ERC20Backing))] +#endif +public interface ERC20 : IContract { [EvmMethodInfo(Name = "balanceOf", View = true)] Task BalanceOf(EvmAddress account); @@ -63,10 +63,10 @@ However, this usually isn't needed, because the `Contract` class automatically i types, such as `EvmAddress` to be `address` and `string` to be `string`. ```csharp -#if UNITY_EDITOR || !ENABLE_MONO -[BackedType(typeof(ERC20Backing))] -#endif -public interface ERC20 : IContract +#if UNITY_EDITOR || !ENABLE_MONO +[BackedType(typeof(ERC20Backing))] +#endif +public interface ERC20 : IContract { [EvmMethodInfo(Name = "balanceOf", View = true)] Task BalanceOf([EvmParameterInfo(Type = "address")] string account); @@ -76,16 +76,16 @@ public interface ERC20 : IContract To define the EVM return type for the function, you can use `EvmParamterInfo` on the return type: ```csharp -#if UNITY_EDITOR || !ENABLE_MONO -[BackedType(typeof(ERC20Backing))] -#endif -public interface ERC20 : IContract +#if UNITY_EDITOR || !ENABLE_MONO +[BackedType(typeof(ERC20Backing))] +#endif +public interface ERC20 : IContract { [EvmMethodInfo(Name = "balanceOf", View = true)] Task BalanceOf(EvmAddress account); - - [EvmMethodInfo(Name = "decimals", View = true)] - [return: EvmParameterInfo(Type = "uint8")] + + [EvmMethodInfo(Name = "decimals", View = true)] + [return: EvmParameterInfo(Type = "uint8")] Task Decimals(); } ``` @@ -110,44 +110,44 @@ Also, do one of the following: - Declare a `static readonly string Bytecode` in the interface that has the bytecode. - ```csharp - #if UNITY_EDITOR || !ENABLE_MONO - [BackedType(typeof(ERC20Backing))] - #endif - public interface ERC20 : IContract - { - public static readonly string Bytecode = "0x6080604052348015620000115760008...."; - - [EvmConstructorMethod] - Task DeployNew(String name_, String symbol_); - - [EvmMethodInfo(Name = "balanceOf", View = true)] - Task BalanceOf(EvmAddress account); - - [EvmMethodInfo(Name = "decimals", View = true)] - [return: EvmParameterInfo(Type = "uint8")] - Task Decimals(); - } - ``` + ```csharp + #if UNITY_EDITOR || !ENABLE_MONO + [BackedType(typeof(ERC20Backing))] + #endif + public interface ERC20 : IContract + { + public static readonly string Bytecode = "0x6080604052348015620000115760008...."; + + [EvmConstructorMethod] + Task DeployNew(String name_, String symbol_); + + [EvmMethodInfo(Name = "balanceOf", View = true)] + Task BalanceOf(EvmAddress account); + + [EvmMethodInfo(Name = "decimals", View = true)] + [return: EvmParameterInfo(Type = "uint8")] + Task Decimals(); + } + ``` - Set the `Bytecode` field in the `EvmConstructorMethod` attribute. - ```csharp - #if UNITY_EDITOR || !ENABLE_MONO - [BackedType(typeof(ERC20Backing))] - #endif - public interface ERC20 : IContract - { - [EvmConstructorMethod(Bytecode = "0x608060405238....")] - Task DeployNew(String name_, String symbol_); - - [EvmMethodInfo(Name = "balanceOf", View = true)] - Task BalanceOf(EvmAddress account); - - [EvmMethodInfo(Name = "decimals", View = true)] - [return: EvmParameterInfo(Type = "uint8")] - Task Decimals(); - } - ``` + ```csharp + #if UNITY_EDITOR || !ENABLE_MONO + [BackedType(typeof(ERC20Backing))] + #endif + public interface ERC20 : IContract + { + [EvmConstructorMethod(Bytecode = "0x608060405238....")] + Task DeployNew(String name_, String symbol_); + + [EvmMethodInfo(Name = "balanceOf", View = true)] + Task BalanceOf(EvmAddress account); + + [EvmMethodInfo(Name = "decimals", View = true)] + [return: EvmParameterInfo(Type = "uint8")] + Task Decimals(); + } + ``` By default, the [contract code generator](index.md#generate-contract-code) uses the second option. diff --git a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-proxy-class.md b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-proxy-class.md index aafa9fe280a..5ace52517d9 100644 --- a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-proxy-class.md +++ b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-proxy-class.md @@ -29,5 +29,5 @@ You should never need to inherit the `Contract` class, unless you're using the However, the [contract code generator](index.md#generate-contract-code) already generates these classes for you. -You only need to use `Contract.Attach(string address, IProvider provider)`. +You only need to use `Contract.Attach(string address, IProvider provider)`. ::: diff --git a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/index.md b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/index.md index c70649b04e3..9c20f80663b 100644 --- a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/index.md +++ b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/index.md @@ -60,7 +60,7 @@ public async void Start() { var metaMask = MetaMaskUnity.Instance.Wallet; var address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; - + ERC20 usdc = Contract.Attach(address, metaMask); } ``` diff --git a/wallet/how-to/use-sdk/gaming/unreal-engine.md b/wallet/how-to/use-sdk/gaming/unreal-engine.md index 8d965fd2c09..3acea2c7965 100644 --- a/wallet/how-to/use-sdk/gaming/unreal-engine.md +++ b/wallet/how-to/use-sdk/gaming/unreal-engine.md @@ -7,4 +7,4 @@ sidebar_position: 2 [MetaMask SDK](../../../concepts/sdk/index.md) support for Unreal Engine games is coming soon. The SDK currently supports [Unity](unity/index.md) gaming dapps, -[JavaScript-based](../javascript/index.md) dapps, and [mobile](../mobile/index.md) dapps. +[JavaScript-based](../javascript/index.md) dapps, and [mobile](../mobile/index.md) dapps. \ No newline at end of file diff --git a/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests.md b/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests.md index 14c770714fd..1ac3f8f83d8 100644 --- a/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests.md +++ b/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests.md @@ -50,7 +50,7 @@ The following is an example of using `metamask_batch` to batch [`eth_sendTransaction`](/wallet/reference/eth_sendtransaction) in React, Next.js, or React Native/Expo: ```javascript title="index.js" -import { metamask_batch } from "metamask-sdk" +import { metamask_batch } from "metamask-sdk"; function MyComponent() { const handleBatchRequest = async () => { @@ -64,17 +64,17 @@ function MyComponent() { }, ], }, - ] + ]; try { - const results = await metamask_batch(batchRequests) - console.log(results) // Process results. + const results = await metamask_batch(batchRequests); + console.log(results); // Process results. } catch (error) { - console.error("Batch request failed", error) + console.error("Batch request failed", error); } - } + }; - return + return ; } ``` diff --git a/wallet/how-to/use-sdk/javascript/connect-and-sign.md b/wallet/how-to/use-sdk/javascript/connect-and-sign.md index 99732ab2e28..7dcfb64c4e9 100644 --- a/wallet/how-to/use-sdk/javascript/connect-and-sign.md +++ b/wallet/how-to/use-sdk/javascript/connect-and-sign.md @@ -47,12 +47,12 @@ const connectAndSign = async () => { try { const signResult = await sdk?.connectAndSign({ msg: "Connect + Sign message", - }) - setResponse(signResult) + }); + setResponse(signResult); } catch (err) { - console.warn("failed to connect..", err) + console.warn("failed to connect..", err); } -} +}; ``` To invoke `connectAndSign`: @@ -67,29 +67,29 @@ The following is an example of using the `connectAndSign` method in a React dapp into a functional component: ```javascript -import React, { useState } from "react" -import { useSDK } from "@metamask/sdk-react" +import React, { useState } from "react"; +import { useSDK } from "@metamask/sdk-react"; function MyComponent() { - const { sdk } = useSDK() - const [signedMessage, setSignedMessage] = useState("") + const { sdk } = useSDK(); + const [signedMessage, setSignedMessage] = useState(""); const handleConnectAndSign = async () => { try { - const message = "Your message here" - const signature = await sdk.connectAndSign({ msg: message }) - setSignedMessage(signature) + const message = "Your message here"; + const signature = await sdk.connectAndSign({ msg: message }); + setSignedMessage(signature); } catch (error) { - console.error("Error in signing:", error) + console.error("Error in signing:", error); } - } + }; return (
{signedMessage &&

Signed Message: {signedMessage}

}
- ) + ); } ``` @@ -105,4 +105,4 @@ in the JavaScript SDK GitHub repository. [`eth_requestAccounts`]: /wallet/reference/eth_requestAccounts -[`personal_sign`]: /wallet/reference/personal_sign +[`personal_sign`]: /wallet/reference/personal_sign \ No newline at end of file diff --git a/wallet/how-to/use-sdk/javascript/display-custom-modals.md b/wallet/how-to/use-sdk/javascript/display-custom-modals.md index ee09ce8484a..2793a0f8087 100644 --- a/wallet/how-to/use-sdk/javascript/display-custom-modals.md +++ b/wallet/how-to/use-sdk/javascript/display-custom-modals.md @@ -27,15 +27,15 @@ This example uses the [MetaMask React SDK](react/index.md). Create a custom modal component that aligns with your dapp's design and functionality requirements. ```javascript title="App.js" -import React from "react" +import React from "react"; const CustomModal = ({ onClose }) => (
-) +); -export default CustomModal +export default CustomModal; ``` ### 2. Implement custom modal logic @@ -46,48 +46,47 @@ for scenarios such as when MetaMask isn't installed. For example: ```javascript title="index.js" -import { MetaMaskProvider } from "@metamask/sdk-react" -import CustomModal from "./CustomModal" -import ReactDOM from "react-dom" +import { MetaMaskProvider } from "@metamask/sdk-react"; +import CustomModal from "./CustomModal"; +import ReactDOM from "react-dom"; const App = () => ( { - let modalContainer = null + let modalContainer = null; return { mount: () => { - modalContainer = document.createElement("div") - document.body.appendChild(modalContainer) + modalContainer = document.createElement("div"); + document.body.appendChild(modalContainer); ReactDOM.render( - { - ReactDOM.unmountComponentAtNode(modalContainer) - modalContainer.remove() + { + ReactDOM.unmountComponentAtNode(modalContainer); + modalContainer.remove(); }} />, modalContainer - ) + ); }, unmount: () => { if (modalContainer) { - ReactDOM.unmountComponentAtNode(modalContainer) - modalContainer.remove() + ReactDOM.unmountComponentAtNode(modalContainer); + modalContainer.remove(); } }, - } + }; }, }, }} > {/* Other components */} -) +); -export default App +export default App; ``` ### 3. Test your custom modal diff --git a/wallet/how-to/use-sdk/javascript/index.md b/wallet/how-to/use-sdk/javascript/index.md index 100f2a6466d..4cae2ada789 100644 --- a/wallet/how-to/use-sdk/javascript/index.md +++ b/wallet/how-to/use-sdk/javascript/index.md @@ -49,7 +49,7 @@ npm i @metamask/sdk In your project script, add the following to import the SDK: ```javascript title="index.js" -import { MetaMaskSDK } from "@metamask/sdk" +import { MetaMaskSDK } from "@metamask/sdk"; ``` ### 3. Instantiate the SDK @@ -64,10 +64,10 @@ const MMSDK = new MetaMaskSDK({ }, infuraAPIKey: process.env.INFURA_API_KEY, // Other options. -}) +}); // You can also access via window.ethereum. -const ethereum = MMSDK.getProvider() +const ethereum = MMSDK.getProvider(); ``` - Use [`dappMetadata`](../../../reference/sdk-js-options.md#dappmetadata) to display information @@ -85,7 +85,7 @@ Always call [`eth_requestAccounts`](/wallet/reference/eth_requestaccounts) using prompts the installation or connection popup to appear. ```javascript -ethereum.request({ method: "eth_requestAccounts", params: [] }) +ethereum.request({ method: "eth_requestAccounts", params: [] }); ``` You can also call the SDK's [`connectAndSign`](connect-and-sign.md) method, and @@ -96,7 +96,7 @@ You can also call the SDK's [`connectAndSign`](connect-and-sign.md) method, and You can copy the full JavaScript example to get started: ```javascript title="index.js" -import { MetaMaskSDK } from "@metamask/sdk" +import { MetaMaskSDK } from "@metamask/sdk"; const MMSDK = new MetaMaskSDK({ dappMetadata: { @@ -105,12 +105,12 @@ const MMSDK = new MetaMaskSDK({ }, infuraAPIKey: process.env.INFURA_API_KEY, // Other options. -}) +}); // You can also access via window.ethereum. -const ethereum = MMSDK.getProvider() +const ethereum = MMSDK.getProvider(); -ethereum.request({ method: "eth_requestAccounts", params: [] }) +ethereum.request({ method: "eth_requestAccounts", params: [] }); ``` See the [example JavaScript dapps](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples) diff --git a/wallet/how-to/use-sdk/javascript/make-read-only-requests.md b/wallet/how-to/use-sdk/javascript/make-read-only-requests.md index 85691279fc8..7d6f0336c26 100644 --- a/wallet/how-to/use-sdk/javascript/make-read-only-requests.md +++ b/wallet/how-to/use-sdk/javascript/make-read-only-requests.md @@ -27,7 +27,7 @@ Your dapp cannot directly call the following RPC methods, which require user wal - `wallet_watchAsset` - `wallet_addEthereumChain` - `wallet_switchEthereumChain` - ::: +::: Configure your dapp to make read-only requests using the [Infura API](#use-the-infura-api), [custom nodes](#use-custom-nodes), or [both](#use-the-infura-api-and-custom-nodes). @@ -119,7 +119,7 @@ sdkOptions={{ }, defaultReadOnlyChainId: "0x1", // Other options. -}} +} ``` In this example, read-only requests to Mainnet (chain ID `0x1`) use the Infura API, while read-only diff --git a/wallet/how-to/use-sdk/javascript/nodejs.md b/wallet/how-to/use-sdk/javascript/nodejs.md index 6cde07e5852..ede4133a897 100644 --- a/wallet/how-to/use-sdk/javascript/nodejs.md +++ b/wallet/how-to/use-sdk/javascript/nodejs.md @@ -33,7 +33,7 @@ npm i @metamask/sdk In your project script, add the following to import the SDK: ```javascript title="index.js" -import { MetaMaskSDK } from "@metamask/sdk" +import { MetaMaskSDK } from "@metamask/sdk"; ``` ### 3. Instantiate the SDK @@ -48,10 +48,10 @@ const MMSDK = new MetaMaskSDK({ }, infuraAPIKey: process.env.INFURA_API_KEY, // Other options. -}) +}); // You can also access via window.ethereum -const ethereum = MMSDK.getProvider() +const ethereum = MMSDK.getProvider(); ``` - Use [`dappMetadata`](../../../reference/sdk-js-options.md#dappmetadata) to display information @@ -69,7 +69,7 @@ Always call [`eth_requestAccounts`](/wallet/reference/eth_requestaccounts) using prompts the installation or connection popup to appear. ```javascript -ethereum.request({ method: "eth_requestAccounts", params: [] }) +ethereum.request({ method: "eth_requestAccounts", params: [] }); ``` You can also call the SDK's [`connectAndSign`](connect-and-sign.md) method, and @@ -80,7 +80,7 @@ You can also call the SDK's [`connectAndSign`](connect-and-sign.md) method, and You can copy the full Node.js example to get started: ```javascript title="index.js" -import { MetaMaskSDK } from "@metamask/sdk" +import { MetaMaskSDK } from "@metamask/sdk"; const MMSDK = new MetaMaskSDK({ dappMetadata: { @@ -89,12 +89,12 @@ const MMSDK = new MetaMaskSDK({ }, infuraAPIKey: process.env.INFURA_API_KEY, // Other options. -}) +}); // You can also access via window.ethereum -const ethereum = MMSDK.getProvider() +const ethereum = MMSDK.getProvider(); -ethereum.request({ method: "eth_requestAccounts", params: [] }) +ethereum.request({ method: "eth_requestAccounts", params: [] }); ``` See the [example Node.js dapp](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/nodejs) diff --git a/wallet/how-to/use-sdk/javascript/other-web-frameworks.md b/wallet/how-to/use-sdk/javascript/other-web-frameworks.md index 2f5c54dcea4..7c75ba74c5a 100644 --- a/wallet/how-to/use-sdk/javascript/other-web-frameworks.md +++ b/wallet/how-to/use-sdk/javascript/other-web-frameworks.md @@ -34,7 +34,7 @@ npm i @metamask/sdk In your project script, add the following to import the SDK: ```javascript title="index.js" -import { MetaMaskSDK } from "@metamask/sdk" +import { MetaMaskSDK } from "@metamask/sdk"; ``` ### 3. Instantiate the SDK @@ -42,14 +42,14 @@ import { MetaMaskSDK } from "@metamask/sdk" Instantiate the SDK using any [options](../../../reference/sdk-js-options.md): ```javascript title="index.js" -const MMSDK = new MetaMaskSDK({ +const MMSDK = new MetaMaskSDK( dappMetadata: { name: "Example JavaScript Dapp", url: window.location.href, }, infuraAPIKey: process.env.INFURA_API_KEY, // Other options -}); +); // You can also access via window.ethereum const ethereum = MMSDK.getProvider(); @@ -70,7 +70,7 @@ Always call [`eth_requestAccounts`](/wallet/reference/eth_requestaccounts) using prompts the installation or connection popup to appear. ```javascript -ethereum.request({ method: "eth_requestAccounts", params: [] }) +ethereum.request({ method: "eth_requestAccounts", params: [] }); ``` You can also call the SDK's [`connectAndSign`](connect-and-sign.md) method, and @@ -83,14 +83,14 @@ You can copy the full JavaScript example to get started: ```javascript title="index.js" import { MetaMaskSDK } from "@metamask/sdk"; -const MMSDK = new MetaMaskSDK({ +const MMSDK = new MetaMaskSDK( dappMetadata: { name: "Example JavaScript Dapp", url: window.location.href, }, infuraAPIKey: process.env.INFURA_API_KEY, // Other options -}); +); // You can also access via window.ethereum const ethereum = MMSDK.getProvider(); diff --git a/wallet/how-to/use-sdk/javascript/pure-js.md b/wallet/how-to/use-sdk/javascript/pure-js.md index caf89a1f18c..c0978854676 100644 --- a/wallet/how-to/use-sdk/javascript/pure-js.md +++ b/wallet/how-to/use-sdk/javascript/pure-js.md @@ -19,21 +19,21 @@ To import, instantiate, and use the SDK, you can insert a script in the head sec ... ... diff --git a/wallet/how-to/use-sdk/javascript/react-native.md b/wallet/how-to/use-sdk/javascript/react-native.md index 795ecc51f0b..06543c5a3c3 100644 --- a/wallet/how-to/use-sdk/javascript/react-native.md +++ b/wallet/how-to/use-sdk/javascript/react-native.md @@ -6,8 +6,8 @@ tags: - JavaScript SDK --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Use MetaMask SDK with React Native and Expo @@ -28,16 +28,16 @@ Create a new React Native or Expo project using the following commands: -```bash -npx react-native@latest init MyProject -``` + ```bash + npx react-native@latest init MyProject + ``` -```bash -npx create-expo-app devexpo --template -``` + ```bash + npx create-expo-app devexpo --template + ``` @@ -49,16 +49,16 @@ Install the SDK and its dependencies using the following commands: -```bash -npm install eciesjs @metamask/sdk-react ethers@5.7.2 @react-native-async-storage/async-storage node-libs-react-native react-native-background-timer react-native-randombytes react-native-url-polyfill react-native-get-random-values -``` + ```bash + npm install eciesjs @metamask/sdk-react ethers@5.7.2 @react-native-async-storage/async-storage node-libs-react-native react-native-background-timer react-native-randombytes react-native-url-polyfill react-native-get-random-values + ``` -```bash -npx expo install expo-crypto @metamask/sdk-react ethers@5.7.2 @react-native-async-storage/async-storage node-libs-expo react-native-background-timer react-native-randombytes react-native-url-polyfill react-native-get-random-values@1.8.0 -``` + ```bash + npx expo install expo-crypto @metamask/sdk-react ethers@5.7.2 @react-native-async-storage/async-storage node-libs-expo react-native-background-timer react-native-randombytes react-native-url-polyfill react-native-get-random-values@1.8.0 + ``` @@ -76,49 +76,49 @@ In React Native or Expo, update the default Metro configuration file to the foll -```javascript title="metro.config.js" -const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config") + ```javascript title="metro.config.js" + const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config"); -const defaultConfig = getDefaultConfig(__dirname) + const defaultConfig = getDefaultConfig(__dirname); -const config = { - transformer: { - getTransformOptions: async () => ({ - transform: { - experimentalImportSupport: false, - inlineRequires: true, + const config = { + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, + resolver: { + extraNodeModules: { + ...require("node-libs-react-native"), }, - }), - }, - resolver: { - extraNodeModules: { - ...require("node-libs-react-native"), }, - }, -} + }; -module.exports = mergeConfig(defaultConfig, config) -``` + module.exports = mergeConfig(defaultConfig, config); + ``` -```javascript title="metro.config.js" -const config = getDefaultConfig(__dirname) + ```javascript title="metro.config.js" + const config = getDefaultConfig(__dirname); -config.resolver.extraNodeModules = { - ...require("node-libs-expo"), -} + config.resolver.extraNodeModules = { + ...require("node-libs-expo"), + }; -config.transformer.getTransformOptions = async () => ({ - transform: { - experimentalImportSupport: false, - inlineRequires: true, - }, -}) + config.transformer.getTransformOptions = async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }); -module.exports = config -``` + module.exports = config; + ``` @@ -130,20 +130,20 @@ Add the following import statements to the React Native or Expo entry file: -```javascript title="index.js or App.tsx" -import "node-libs-react-native/globals" -import "react-native-url-polyfill/auto" -import "react-native-get-random-values" -``` + ```javascript title="index.js or App.tsx" + import "node-libs-react-native/globals"; + import "react-native-url-polyfill/auto"; + import "react-native-get-random-values"; + ``` -```javascript title="App.tsx" -import "node-libs-expo/globals" -import "react-native-url-polyfill/auto" -import "react-native-get-random-values" -``` + ```javascript title="App.tsx" + import "node-libs-expo/globals"; + import "react-native-url-polyfill/auto"; + import "react-native-get-random-values"; + ``` @@ -165,18 +165,18 @@ Run the React Native or Expo project on Android or iOS using the following comma -```bash -npx react-native run-android -npx react-native run-ios -``` + ```bash + npx react-native run-android + npx react-native run-ios + ``` -```bash -npx expo run:android -npx expo run:ios -``` + ```bash + npx expo run:android + npx expo run:ios + ``` @@ -189,13 +189,13 @@ The following code snippets demonstrate how to use the hook. Import the hook: ```javascript -import { useSDK } from "@metamask/sdk-react" +import { useSDK } from "@metamask/sdk-react"; ``` Initialize the SDK in your main component: ```javascript -const { connect, disconnect, account, chainId, ethereum } = useSDK() +const { connect, disconnect, account, chainId, ethereum } = useSDK(); ``` Connect to MetaMask: @@ -203,11 +203,11 @@ Connect to MetaMask: ```javascript const connectWallet = async () => { try { - await connect() + await connect(); } catch (error) { - console.error("Failed to connect wallet:", error) + console.error("Failed to connect wallet:", error); } -} +}; ``` Handle your dapp's state: @@ -218,15 +218,15 @@ useEffect(() => { if (account && chainId) { // Handle account and network changes. } -}, [account, chainId]) +}, [account, chainId]); ``` Disconnect from MetaMask: ```javascript const disconnectWallet = async () => { - await disconnect() -} + await disconnect(); +}; ``` ## Examples diff --git a/wallet/how-to/use-sdk/javascript/react/index.md b/wallet/how-to/use-sdk/javascript/react/index.md index 715650c1681..c04da19c9ec 100644 --- a/wallet/how-to/use-sdk/javascript/react/index.md +++ b/wallet/how-to/use-sdk/javascript/react/index.md @@ -6,8 +6,8 @@ tags: - JavaScript SDK --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Use MetaMask SDK with React @@ -42,7 +42,7 @@ npm i @metamask/sdk-react In your project script, add the following to import the SDK: ```typescript title="index.tsx" -import { MetaMaskProvider } from "@metamask/sdk-react" +import { MetaMaskProvider } from "@metamask/sdk-react"; ``` ### 3. Wrap your project with `MetaMaskProvider` @@ -155,12 +155,12 @@ const connectAndSign = async () => { try { const signResult = await sdk?.connectAndSign({ msg: "Connect + Sign message", - }) - setResponse(signResult) + }); + setResponse(signResult); } catch (err) { - console.warn("failed to connect..", err) + console.warn("failed to connect..", err); } -} +}; ``` You can also [batch multiple JSON-RPC requests](../batch-json-rpc-requests.md) using the diff --git a/wallet/how-to/use-sdk/javascript/react/react-ui.md b/wallet/how-to/use-sdk/javascript/react/react-ui.md index 5baab2357d6..b64709fb610 100644 --- a/wallet/how-to/use-sdk/javascript/react/react-ui.md +++ b/wallet/how-to/use-sdk/javascript/react/react-ui.md @@ -6,8 +6,8 @@ tags: - JavaScript SDK --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Use MetaMask SDK with React UI @@ -44,7 +44,7 @@ npm i @metamask/sdk-react-ui In your project script, add the following to import the SDK: ```javascript title="index.js" -import { MetaMaskUIProvider } from "@metamask/sdk-react-ui" +import { MetaMaskUIProvider } from "@metamask/sdk-react-ui"; ``` ### 3. Wrap your project with `MetaMaskUIProvider` @@ -103,16 +103,16 @@ connection to MetaMask. You can use it as follows: ```js title="App.js" -import { MetaMaskButton } from "@metamask/sdk-react-ui" -import React, { useState } from "react" +import { MetaMaskButton } from "@metamask/sdk-react-ui"; +import React, { useState } from "react"; export const App = () => { return (
- ) -} + ); +}; ```
@@ -169,8 +169,8 @@ import { useAccount, useSDK, useSignMessage, -} from "@metamask/sdk-react-ui" -import "./App.css" +} from "@metamask/sdk-react-ui"; +import "./App.css"; function AppReady() { const { @@ -181,9 +181,9 @@ function AppReady() { signMessage, } = useSignMessage({ message: "gm wagmi frens", - }) + }); - const { isConnected } = useAccount() + const { isConnected } = useAccount(); return (
@@ -192,7 +192,10 @@ function AppReady() { {isConnected && ( <>
- {isSignSuccess &&
Signature: {signData}
} @@ -202,20 +205,20 @@ function AppReady() { )}
- ) + ); } function App() { - const { ready } = useSDK() + const { ready } = useSDK(); if (!ready) { - return
Loading...
+ return
Loading...
; } - return + return ; } -export default App +export default App; ``` diff --git a/wallet/how-to/use-sdk/mobile/android.md b/wallet/how-to/use-sdk/mobile/android.md index 7c603e33c2e..5d3108f1086 100644 --- a/wallet/how-to/use-sdk/mobile/android.md +++ b/wallet/how-to/use-sdk/mobile/android.md @@ -13,9 +13,8 @@ Import [MetaMask SDK](../../../concepts/sdk/index.md) into your native Android d your users to easily connect with their MetaMask Mobile wallet. :::tip See also - - [Android SDK architecture](../../../concepts/sdk/android.md) - ::: +::: ## Prerequisites @@ -56,10 +55,10 @@ import io.metamask.androidsdk.Ethereum You can connect your dapp to MetaMask in one of two ways: 1. [Use the `ethereum` provider object directly](#31-use-the-provider-object-directly). - We recommend using this method in a pure model layer. + We recommend using this method in a pure model layer. 2. [Use a ViewModel](#32-use-a-viewmodel) that injects the `ethereum` provider object. - We recommend using this method at the app level, because it provides a single instance that - survives configuration changes and can be shared across all views. + We recommend using this method at the app level, because it provides a single instance that + survives configuration changes and can be shared across all views. :::note Logging By default, MetaMask logs three SDK events: `connection_request`, `connected`, and `disconnected`. diff --git a/wallet/how-to/use-sdk/mobile/ios.md b/wallet/how-to/use-sdk/mobile/ios.md index 7d57c21e5c3..9056939572e 100644 --- a/wallet/how-to/use-sdk/mobile/ios.md +++ b/wallet/how-to/use-sdk/mobile/ios.md @@ -7,8 +7,8 @@ tags: - iOS SDK --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Use MetaMask SDK with iOS diff --git a/wallet/index.mdx b/wallet/index.mdx index 0e1878e5574..07cf3ac6d16 100644 --- a/wallet/index.mdx +++ b/wallet/index.mdx @@ -2,7 +2,7 @@ title: Introduction --- -import CardList from "@site/src/components/CardList" +import CardList from '@site/src/components/CardList' # Integrate your dapp with the MetaMask wallet @@ -14,14 +14,12 @@ You can interact with your users' Ethereum accounts, performing tasks such as th { href: "how-to/connect", title: "↔️ Connect to MetaMask", - description: - "Connect to MetaMask and other wallets in your users' browsers.", + description: "Connect to MetaMask and other wallets in your users' browsers.", }, { href: "how-to/sign-data", title: "🖊️ Sign data", - description: - "Request signatures from users, and allow them to sign in with Ethereum.", + description: "Request signatures from users, and allow them to sign in with Ethereum.", }, { href: "how-to/display", @@ -31,9 +29,8 @@ You can interact with your users' Ethereum accounts, performing tasks such as th { href: "how-to/use-sdk", title: "📱 Connect to extension & mobile", - description: - "Connect to the MetaMask extension and mobile app using MetaMask SDK.", - }, + description: "Connect to the MetaMask extension and mobile app using MetaMask SDK.", + } ]} /> @@ -56,21 +53,18 @@ If you're new to integrating dapps with MetaMask, check out the following topics { href: "concepts/sdk", title: "📱 About MetaMask SDK", - description: - "Learn about the benefits of the SDK and how the SDK connects to MetaMask.", + description: "Learn about the benefits of the SDK and how the SDK connects to MetaMask.", }, { href: "tutorials/react-dapp-local-state", title: "🛠️ Create a React dapp tutorial", - description: - "Follow the tutorial to create a React dapp and integrate it with MetaMask.", + description: "Follow the tutorial to create a React dapp and integrate it with MetaMask.", }, { href: "tutorials/javascript-dapp-simple", title: "🛠️ Create a simple dapp tutorial", - description: - "Follow the tutorial to create a simple dapp and integrate it with MetaMask.", - }, + description: "Follow the tutorial to create a simple dapp and integrate it with MetaMask.", + } ]} /> diff --git a/wallet/reference/new-reference.mdx b/wallet/reference/new-reference.mdx index c7ac519c3d1..5d209868a06 100644 --- a/wallet/reference/new-reference.mdx +++ b/wallet/reference/new-reference.mdx @@ -5,7 +5,7 @@ hide_table_of_contents: true sidebar_class_name: "hidden" --- -import ParserOpenRPC from "@site/src/components/ParserOpenRPC" -import { NETWORK_NAMES } from "@site/src/plugins/plugin-json-rpc" +import ParserOpenRPC from "@site/src/components/ParserOpenRPC"; +import { NETWORK_NAMES } from "@site/src/plugins/plugin-json-rpc"; - + \ No newline at end of file diff --git a/wallet/reference/provider-api.md b/wallet/reference/provider-api.md index aa6b7220c10..f503b28c168 100644 --- a/wallet/reference/provider-api.md +++ b/wallet/reference/provider-api.md @@ -34,7 +34,7 @@ Non-MetaMask providers may also set this property to `true`. #### Example ```typescript -provider.isMetaMask // Or window.ethereum.isMetaMask if you don't support EIP-6963. +provider.isMetaMask; // Or window.ethereum.isMetaMask if you don't support EIP-6963. ``` ## Methods @@ -62,7 +62,7 @@ None. #### Example ```typescript -provider.isConnected() // Or window.ethereum.isConnected() if you don't support EIP-6963. +provider.isConnected(); // Or window.ethereum.isConnected() if you don't support EIP-6963. ``` ### `request()` @@ -100,7 +100,7 @@ provider // Or window.ethereum if you don't support EIP-6963. value: "0x9184e72a", // 2441406250 data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", }, - ], + ] }) .then((result) => { // The result varies by RPC method. @@ -108,7 +108,7 @@ provider // Or window.ethereum if you don't support EIP-6963. }) .catch((error) => { // If the request fails, the Promise rejects with an error. - }) + }); ``` ### `_metamask.isUnlocked()` @@ -133,7 +133,7 @@ A promise that resolves to `true` if MetaMask is unlocked by the user, and `fals #### Example ```typescript -provider._metamask.isUnlocked() // Or window.ethereum._metamask.isUnlocked() if you don't support EIP-6963. +provider._metamask.isUnlocked(); // Or window.ethereum._metamask.isUnlocked() if you don't support EIP-6963. ``` ## Events @@ -151,12 +151,12 @@ function handleAccountsChanged(accounts) { } provider // Or window.ethereum if you don't support EIP-6963. - .on("accountsChanged", handleAccountsChanged) + .on("accountsChanged", handleAccountsChanged); // Later provider // Or window.ethereum if you don't support EIP-6963. - .removeListener("accountsChanged", handleAccountsChanged) + .removeListener("accountsChanged", handleAccountsChanged); ``` ### `accountsChanged` @@ -193,7 +193,7 @@ We strongly recommend reloading the page upon chain changes, unless you have a g ```typescript provider // Or window.ethereum if you don't support EIP-6963. - .on("chainChanged", (chainId) => window.location.reload()) + .on("chainChanged", (chainId) => window.location.reload()); ``` ::: @@ -253,22 +253,22 @@ subscription update is emitted as a `message` event with a `type` of `eth_subscr #### `removeListener` -Use the `removeListener` method to remove specific event listeners from an `EventEmitter` object. +Use the `removeListener` method to remove specific event listeners from an `EventEmitter` object. In the following example `removeListener` is used to remove the `connect` and `accountsChanged` events: ```javascript // Use window.ethereum instead of provider if EIP-6963 is not supported. // Add listeners -provider.on("_initialized", updateWalletAndAccounts) -provider.on("connect", updateWalletAndAccounts) -provider.on("accountsChanged", updateWallet) -provider.on("chainChanged", updateWalletAndAccounts) -provider.on("disconnect", disconnectWallet) +provider.on("_initialized", updateWalletAndAccounts); +provider.on("connect", updateWalletAndAccounts); +provider.on("accountsChanged", updateWallet); +provider.on("chainChanged", updateWalletAndAccounts); +provider.on("disconnect", disconnectWallet); // Remove individual listeners -provider.removeListener("connect", updateWalletAndAccounts) -provider.removeListener("accountsChanged", updateWallet) +provider.removeListener("connect", updateWalletAndAccounts); +provider.removeListener("accountsChanged", updateWallet); ``` The first argument of `removeListener` is the event name, and the second argument is @@ -276,12 +276,12 @@ a reference to the function passed to `on` for the event. #### `removeAllListeners` -You can use `removeAllListeners` to remove all listeners from the event emitter at once. This method is helpful when you need to clean up all listeners simultaneously. +You can use `removeAllListeners` to remove all listeners from the event emitter at once. This method is helpful when you need to clean up all listeners simultaneously. :::caution Use `removeAllListeners` with caution. -This method clears all event listeners associated with the emitter, not only the listeners set up by the application code. +This method clears all event listeners associated with the emitter, not only the listeners set up by the application code. Using this method can unexpectedly clear important event handlers, interfere with scripts, and make debugging more complex. You can use the `removeListener` method to safely remove specific listeners. @@ -291,11 +291,11 @@ You can use the `removeListener` method to safely remove specific listeners. // Use window.ethereum instead of provider if EIP-6963 is not supported. // Add listeners -provider.on("_initialized", updateWalletAndAccounts) -provider.on("connect", updateWalletAndAccounts) -provider.on("accountsChanged", updateWallet) -provider.on("chainChanged", updateWalletAndAccounts) -provider.on("disconnect", disconnectWallet) +provider.on("_initialized", updateWalletAndAccounts); +provider.on("connect", updateWalletAndAccounts); +provider.on("accountsChanged", updateWallet); +provider.on("chainChanged", updateWalletAndAccounts); +provider.on("disconnect", disconnectWallet); // Remove all listeners provider.removeAllListeners() @@ -309,9 +309,9 @@ All errors returned by the MetaMask provider follow this interface: ```typescript interface ProviderRpcError extends Error { - message: string - code: number - data?: unknown + message: string; + code: number; + data?: unknown; } ``` diff --git a/wallet/reference/sdk-js-options.md b/wallet/reference/sdk-js-options.md index ea41c197743..99c770cbf1f 100644 --- a/wallet/reference/sdk-js-options.md +++ b/wallet/reference/sdk-js-options.md @@ -5,8 +5,8 @@ tags: - JavaScript SDK --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # JavaScript SDK options @@ -474,4 +474,4 @@ wakeLockType: Temporary The type of wake lock to use when the SDK is running in the background. -Options are `Disabled`, `Temporary`, and `UntilResponse`. +Options are `Disabled`, `Temporary`, and `UntilResponse`. \ No newline at end of file diff --git a/wallet/tutorials/javascript-dapp-simple.md b/wallet/tutorials/javascript-dapp-simple.md index 9299393ddf6..550fe9edbdf 100644 --- a/wallet/tutorials/javascript-dapp-simple.md +++ b/wallet/tutorials/javascript-dapp-simple.md @@ -3,14 +3,14 @@ description: Create a simple dapp to integrate with MetaMask. sidebar_position: 3 --- -# Create a simple dapp +# Create a simple dapp -This tutorial walks you through creating a simple JavaScript dapp and integrating it with MetaMask. +This tutorial walks you through creating a simple JavaScript dapp and integrating it with MetaMask. It demonstrates the basics of connecting to MetaMask: detecting the MetaMask provider, detecting the user's network, and accessing the user's accounts. :::caution Learning tutorial This tutorial is for educational purposes and connects to MetaMask using the legacy provider object, `window.ethereum`, for the sake of simplicity. -For deployment in a production environment, we recommend [connecting to MetaMask using EIP-6963](../how-to/connect/index.md) instead. +For deployment in a production environment, we recommend [connecting to MetaMask using EIP-6963](../how-to/connect/index.md) instead. [EIP-6963](https://eips.ethereum.org/EIPS/eip-6963) introduces an alternative wallet detection mechanism to the `window.ethereum` provider, and enables dapps to support [wallet interoperability](../concepts/wallet-interoperability.md). @@ -62,7 +62,7 @@ import "./style.css" document.querySelector("#app").innerHTML = ` -

Account:

` +

Account:

`; ``` Update `index.html` to include the script: @@ -105,26 +105,26 @@ mkdir src && touch src/detect.js In a text editor, add the following code to `src/detect.js` to detect the MetaMask provider using `@metamask/detect-provider`: ```js title="detect.js" -import detectEthereumProvider from "@metamask/detect-provider" +import detectEthereumProvider from "@metamask/detect-provider"; async function setup() { - const provider = await detectEthereumProvider() + const provider = await detectEthereumProvider(); if (provider && provider === window.ethereum) { - console.log("MetaMask is available!") - startApp(provider) // Initialize your dapp with MetaMask. + console.log("MetaMask is available!"); + startApp(provider); // Initialize your dapp with MetaMask. } else { - console.log("Please install MetaMask!") + console.log("Please install MetaMask!"); } } function startApp(provider) { if (provider !== window.ethereum) { - console.error("Do you have multiple wallets installed?") + console.error("Do you have multiple wallets installed?"); } } -window.addEventListener("load", setup) +window.addEventListener("load", setup); ``` ### 4. Detect a user's network @@ -137,13 +137,15 @@ RPC method to detect the chain ID of the user's current network, and listens to user changes networks: ```js title="detect.js" -const chainId = await window.ethereum.request({ method: "eth_chainId" }) +const chainId = await window.ethereum + .request({ method: "eth_chainId" }); -window.ethereum.on("chainChanged", handleChainChanged) +window.ethereum + .on("chainChanged", handleChainChanged); function handleChainChanged(chainId) { // We recommend reloading the page, unless you must do otherwise. - window.location.reload() + window.location.reload(); } ``` @@ -161,12 +163,12 @@ Selecting the button activates the call to `eth_requestAccounts`, allowing you t // You should only attempt to request the user's account in response to user interaction, such as // selecting a button. Otherwise, you risk spamming the user. If you fail to retrieve // the user's account, you should encourage the user to initiate the attempt. -const ethereumButton = document.querySelector(".enableEthereumButton") -const showAccount = document.querySelector(".showAccount") +const ethereumButton = document.querySelector(".enableEthereumButton"); +const showAccount = document.querySelector(".showAccount"); ethereumButton.addEventListener("click", () => { - getAccount() -}) + getAccount(); +}); // While awaiting the call to eth_requestAccounts, you should disable any buttons the user can // select to initiate the request. MetaMask rejects any additional requests while the first is still @@ -174,17 +176,17 @@ ethereumButton.addEventListener("click", () => { async function getAccount() { const accounts = await window.ethereum .request({ method: "eth_requestAccounts" }) - .catch((err) => { - if (err.code === 4001) { - // EIP-1193 userRejectedRequest error. - // If this happens, the user rejected the connection request. - console.log("Please connect to MetaMask.") - } else { - console.error(err) - } - }) - const account = accounts[0] - showAccount.innerHTML = account + .catch((err) => { + if (err.code === 4001) { + // EIP-1193 userRejectedRequest error. + // If this happens, the user rejected the connection request. + console.log("Please connect to MetaMask."); + } else { + console.error(err); + } + }); + const account = accounts[0]; + showAccount.innerHTML = account; } ``` @@ -235,7 +237,7 @@ After connecting, your connected account displays: ## Example -The following code samples contain the full simple dapp JavaScript and HTML code that this tutorial walks through. +The following code samples contain the full simple dapp JavaScript and HTML code that this tutorial walks through. You can copy the following full examples to get started quickly. ### JavaScript @@ -245,62 +247,64 @@ You can copy the following full examples to get started quickly. /* Detect the MetaMask Ethereum provider */ /*****************************************/ -import detectEthereumProvider from "@metamask/detect-provider" +import detectEthereumProvider from "@metamask/detect-provider"; async function setup() { - const provider = await detectEthereumProvider() + const provider = await detectEthereumProvider(); if (provider && provider === window.ethereum) { - console.log("MetaMask is available!") - startApp(provider) + console.log("MetaMask is available!"); + startApp(provider); } else { - console.log("Please install MetaMask!") + console.log("Please install MetaMask!"); } } function startApp(provider) { if (provider !== window.ethereum) { - console.error("Do you have multiple wallets installed?") + console.error("Do you have multiple wallets installed?"); } } -window.addEventListener("load", setup) +window.addEventListener("load", setup); /**********************************************************/ /* Handle chain (network) and chainChanged (per EIP-1193) */ /**********************************************************/ -const chainId = await window.ethereum.request({ method: "eth_chainId" }) +const chainId = await window.ethereum + .request({ method: "eth_chainId" }); -window.ethereum.on("chainChanged", handleChainChanged) +window.ethereum + .on("chainChanged", handleChainChanged); function handleChainChanged(chainId) { - window.location.reload() + window.location.reload(); } /*********************************************/ /* Access the user's accounts (per EIP-1102) */ /*********************************************/ -const ethereumButton = document.querySelector(".enableEthereumButton") -const showAccount = document.querySelector(".showAccount") +const ethereumButton = document.querySelector(".enableEthereumButton"); +const showAccount = document.querySelector(".showAccount"); ethereumButton.addEventListener("click", () => { - getAccount() -}) + getAccount(); +}); async function getAccount() { const accounts = await window.ethereum .request({ method: "eth_requestAccounts" }) - .catch((err) => { - if (err.code === 4001) { - console.log("Please connect to MetaMask.") - } else { - console.error(err) - } - }) - const account = accounts[0] - showAccount.innerHTML = account + .catch((err) => { + if (err.code === 4001) { + console.log("Please connect to MetaMask."); + } else { + console.error(err); + } + }); + const account = accounts[0]; + showAccount.innerHTML = account; } ``` @@ -329,6 +333,6 @@ async function getAccount() { You've successfully created a simple dapp and connected it to MetaMask using JavaScript, Vite, and the `window.ethereum` provider. With this setup, your dapp can interact with MetaMask and allow users to securely access accounts and send transactions on the Ethereum blockchain. -As a next step, you can create a [React dapp with local state](react-dapp-local-state.md). +As a next step, you can create a [React dapp with local state](react-dapp-local-state.md). This follow-up tutorial walks you through integrating a simple React dapp with MetaMask using a single JSX component for managing local state, and the Vite build tool with React and TypeScript to create the dapp. diff --git a/wallet/tutorials/react-dapp-global-state.md b/wallet/tutorials/react-dapp-global-state.md index 72a6a7a4f19..f4f3d2f0933 100644 --- a/wallet/tutorials/react-dapp-global-state.md +++ b/wallet/tutorials/react-dapp-global-state.md @@ -4,8 +4,8 @@ toc_max_heading_level: 4 sidebar_position: 2 --- -import Tabs from "@theme/Tabs"; -import TabItem from "@theme/TabItem"; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; # Create a React dapp with global state @@ -22,7 +22,7 @@ The final state of the dapp will look like the following: In this tutorial, you'll put the state into a [React Context](https://react.dev/reference/react/useContext) component, creating a [global state](https://react.dev/learn/reusing-logic-with-custom-hooks#custom-hooks-sharing-logic-between-components) -that allows other components and UI elements to benefit from its data and functions. +that allows other components and UI elements to benefit from its data and functions. You'll use `localStorage` to persist the selected wallet, ensuring the last connected wallet state remains intact even after a page refresh. @@ -157,7 +157,7 @@ Add the following CSS code to `WalletError.module.css`: border-radius: 0.5em; height: 36px; padding: 16px; - color: #efefef; + color: #EFEFEF; background-color: transparent; user-select: none; } @@ -276,18 +276,9 @@ interface EIP1193Provider { isStatus?: boolean host?: string path?: string - sendAsync?: ( - request: { method: string; params?: Array }, - callback: (error: Error | null, response: unknown) => void - ) => void - send?: ( - request: { method: string; params?: Array }, - callback: (error: Error | null, response: unknown) => void - ) => void - request: (request: { - method: string - params?: Array - }) => Promise + sendAsync?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + send?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + request: (request: { method: string, params?: Array }) => Promise } // Combines the provider's metadata with an actual provider object, creating a complete picture of a @@ -299,10 +290,10 @@ interface EIP6963ProviderDetail { // Represents the structure of an event dispatched by a wallet to announce its presence based on EIP-6963. type EIP6963AnnounceProviderEvent = { - detail: { - info: EIP6963ProviderInfo + detail:{ + info: EIP6963ProviderInfo, provider: Readonly - } + } } // An error object with optional properties, commonly encountered when handling eth_requestAccounts errors. @@ -322,13 +313,7 @@ Add the following code to `src/hooks/WalletProvider.tsx` to import the context, type alias, and define the context interface for the EIP-6963 provider: ```tsx title="WalletProvider.tsx" -import { - PropsWithChildren, - createContext, - useCallback, - useEffect, - useState, -} from "react" +import { PropsWithChildren, createContext, useCallback, useEffect, useState } from "react" // Type alias for a record where the keys are wallet identifiers and the values are account // addresses or null. @@ -350,7 +335,7 @@ Add the following code to `src/hooks/WalletProvider.tsx` to extend the global `W interface with the custom `eip6963:announceProvider` event: ```tsx title="WalletProvider.tsx" -declare global { +declare global{ interface WindowEventMap { "eip6963:announceProvider": CustomEvent } @@ -399,15 +384,15 @@ export const WalletProvider: React.FC = ({ children }) => { window.addEventListener("eip6963:announceProvider", onAnnouncement) window.dispatchEvent(new Event("eip6963:requestProvider")) - + return () => window.removeEventListener("eip6963:announceProvider", onAnnouncement) }, []) ``` -In this code sample, lines 6–12 are state definitions: +In this code sample, lines 6–12 are state definitions: -- `wallets` - State to hold detected wallets. -- `selectedWalletRdns` - State to hold the Reverse Domain Name System (RDNS) of the selected wallet. +- `wallets` - State to hold detected wallets. +- `selectedWalletRdns` - State to hold the Reverse Domain Name System (RDNS) of the selected wallet. - `selectedAccountByWalletRdns` - State to hold accounts associated with each wallet. - `errorMessage` - State to hold the error message when a wallet throws an error on connection. - `clearError` - Function to clear the state in `errorMessage`. @@ -416,7 +401,7 @@ In this code sample, lines 6–12 are state definitions: Line 14 is the `useEffect` hook and it handles the following: - Local storage retrieval - On mount, it retrieves the saved selected wallet and accounts from local storage. -- Event listener - It adds an event listener for the custom `eip6963:announceProvider` event. +- Event listener - It adds an event listener for the custom `eip6963:announceProvider` event. - State update - When the provider announces itself, it updates the state. - Provider request - It dispatches an event to request existing providers. - Cleanup - It removes the event listener on unmount. @@ -424,40 +409,30 @@ Line 14 is the `useEffect` hook and it handles the following: Add the following code to `src/hooks/WalletProvider.tsx` to connect a wallet and update the component's state: ```tsx title="WalletProvider.tsx" -const connectWallet = useCallback( - async (walletRdns: string) => { - try { - const wallet = wallets[walletRdns] - const accounts = (await wallet.provider.request({ - method: "eth_requestAccounts", - })) as string[] - - if (accounts?.[0]) { - setSelectedWalletRdns(wallet.info.rdns) - setSelectedAccountByWalletRdns((currentAccounts) => ({ - ...currentAccounts, - [wallet.info.rdns]: accounts[0], - })) - - localStorage.setItem("selectedWalletRdns", wallet.info.rdns) - localStorage.setItem( - "selectedAccountByWalletRdns", - JSON.stringify({ - ...selectedAccountByWalletRdns, - [wallet.info.rdns]: accounts[0], - }) - ) - } - } catch (error) { - console.error("Failed to connect to provider:", error) - const walletError: WalletError = error as WalletError - setError( - `Code: ${walletError.code} \nError Message: ${walletError.message}` - ) +const connectWallet = useCallback(async (walletRdns: string) => { + try { + const wallet = wallets[walletRdns] + const accounts = await wallet.provider.request({method:"eth_requestAccounts"}) as string[] + + if(accounts?.[0]) { + setSelectedWalletRdns(wallet.info.rdns) + setSelectedAccountByWalletRdns((currentAccounts) => ({ + ...currentAccounts, + [wallet.info.rdns]: accounts[0], + })) + + localStorage.setItem("selectedWalletRdns", wallet.info.rdns) + localStorage.setItem("selectedAccountByWalletRdns", JSON.stringify({ + ...selectedAccountByWalletRdns, + [wallet.info.rdns]: accounts[0], + })) } - }, - [wallets, selectedAccountByWalletRdns] -) + } catch (error) { + console.error("Failed to connect to provider:", error) + const walletError: WalletError = error as WalletError + setError(`Code: ${walletError.code} \nError Message: ${walletError.message}`) + } +}, [wallets, selectedAccountByWalletRdns]) ``` This code uses the `walletRdns` parameter to identify the wallet's RDNS for connecting. @@ -474,17 +449,17 @@ const disconnectWallet = useCallback(async () => { [selectedWalletRdns]: null, })) - const wallet = wallets[selectedWalletRdns] + const wallet = wallets[selectedWalletRdns]; setSelectedWalletRdns(null) localStorage.removeItem("selectedWalletRdns") try { await wallet.provider.request({ method: "wallet_revokePermissions", - params: [{ eth_accounts: {} }], - }) + params: [{ "eth_accounts": {} }] + }); } catch (error) { - console.error("Failed to revoke permissions:", error) + console.error("Failed to revoke permissions:", error); } } }, [selectedWalletRdns, wallets]) @@ -503,7 +478,7 @@ will still execute.

Both of the previous functions use `useCallback`. It is used to memoize the `connectWallet` function, optimize performance, and prevent unnecessary re-renders. -It ensures the function instance remains consistent between renders if its dependencies are changed. +It ensures the function instance remains consistent between renders if its dependencies are changed. For example, when using `disconnectWallet`, each time the `WalletProvider` component re-renders without `useCallback`, a new instance of `disconnectWallet` is created. @@ -515,7 +490,6 @@ re-renders of child components. Although `useCallback` is not strictly necessary, it demonstrates best practices. Predicting how a context provider will be used or how the dapp might change or scale is difficult. Using `useCallback` can improve performance in some cases by reducing unnecessary re-renders. -

@@ -524,12 +498,8 @@ Add the following code to `src/hooks/WalletProvider.tsx` to bundle the state and ```tsx title="WalletProvider.tsx" const contextValue: WalletProviderContext = { wallets, - selectedWallet: - selectedWalletRdns === null ? null : wallets[selectedWalletRdns], - selectedAccount: - selectedWalletRdns === null - ? null - : selectedAccountByWalletRdns[selectedWalletRdns], + selectedWallet: selectedWalletRdns === null ? null : wallets[selectedWalletRdns], + selectedAccount: selectedWalletRdns === null ? null : selectedAccountByWalletRdns[selectedWalletRdns], errorMessage, connectWallet, disconnectWallet, @@ -537,16 +507,16 @@ const contextValue: WalletProviderContext = { } return ( - - {children} - + + {children} + ) ``` In the return statement, the `contextValue` object is constructed with all necessary state and functions related to wallet management. It is passed to the `WalletProviderContext.Provider`, making wallet-related data and functions -available to all descendant components. +available to all descendant components. The context provider wraps the children components, allowing them to access the context values. Add the following code to `src/hooks/useWalletProvider.tsx` to provide a custom hook that simplifies @@ -579,7 +549,7 @@ export const formatChainAsNum = (chainIdHex: string) => { } export const formatAddress = (addr: string) => { - const upperAfterLastTwo = addr.slice(0, 2) + addr.slice(2) + const upperAfterLastTwo = addr.slice(0,2) + addr.slice(2) return `${upperAfterLastTwo.substring(0, 5)}...${upperAfterLastTwo.substring(39)}` } ``` @@ -608,14 +578,14 @@ import { WalletProvider } from "~/hooks/WalletProvider" function App() { return ( - {/* + {/*
*/}
- ) + ) } export default App @@ -638,22 +608,19 @@ export const WalletList = () => { <>

Wallets Detected:

- {Object.keys(wallets).length > 0 ? ( - Object.values(wallets).map((provider: EIP6963ProviderDetail) => ( - - )) - ) : ( -
there are no Announced Providers
- )} + { + Object.keys(wallets).length > 0 + ? Object.values(wallets).map((provider: EIP6963ProviderDetail) => ( + + )) + :
there are no Announced Providers
+ }
- ) + ) } ``` @@ -681,41 +648,31 @@ import { formatAddress } from "~/utils" import styles from "./SelectedWallet.module.css" export const SelectedWallet = () => { - const { selectedWallet, selectedAccount, disconnectWallet } = - useWalletProvider() + const { selectedWallet, selectedAccount, disconnectWallet } = useWalletProvider() return ( <> -

- {selectedAccount ? "" : "No "}Wallet Selected -

- {selectedAccount && ( +

{selectedAccount ? "" : "No "}Wallet Selected

+ {selectedAccount && <>
- {selectedWallet.info.name} + {selectedWallet.info.name}
{selectedWallet.info.name}
({formatAddress(selectedAccount)})
-
- uuid: {selectedWallet.info.uuid} -
-
- rdns: {selectedWallet.info.rdns} -
+
uuid: {selectedWallet.info.uuid}
+
rdns: {selectedWallet.info.rdns}
- )} + } - ) + ) } ``` The code in lines 11-22 have conditional rendering, ensuring that the content inside is only displayed if `selectedAccount` is true. This ensures that detailed information about the selected wallet is only displayed when an active -wallet is connected. +wallet is connected. You can display information about the wallet, and conditionally render anything related to the following: @@ -742,17 +699,14 @@ export const WalletError = () => { const isError = !!errorMessage return ( -
- {isError && ( +
+ {isError &&
Error: {errorMessage}
- )} + }
- ) + ) } ``` @@ -787,7 +741,7 @@ function App() { - ) + ) } export default App diff --git a/wallet/tutorials/react-dapp-local-state.md b/wallet/tutorials/react-dapp-local-state.md index 9f8766ca131..53fe0587ae0 100644 --- a/wallet/tutorials/react-dapp-local-state.md +++ b/wallet/tutorials/react-dapp-local-state.md @@ -108,18 +108,9 @@ interface EIP1193Provider { isStatus?: boolean host?: string path?: string - sendAsync?: ( - request: { method: string; params?: Array }, - callback: (error: Error | null, response: unknown) => void - ) => void - send?: ( - request: { method: string; params?: Array }, - callback: (error: Error | null, response: unknown) => void - ) => void - request: (request: { - method: string - params?: Array - }) => Promise + sendAsync?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + send?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + request: (request: { method: string, params?: Array }) => Promise } // Combines the provider's metadata with an actual provider object, creating a complete picture of a @@ -131,7 +122,7 @@ interface EIP6963ProviderDetail { // Represents the structure of an event dispatched by a wallet to announce its presence based on EIP-6963. type EIP6963AnnounceProviderEvent = { - detail: { + detail:{ info: EIP6963ProviderInfo provider: EIP1193Provider } @@ -154,7 +145,7 @@ Create a `src/hooks` directory, and create a file `store.ts` in that directory w ```ts title="store.ts" // Extends WindowEventMap interface, including a custom event eip6963:announceProvider. -declare global { +declare global{ interface WindowEventMap { "eip6963:announceProvider": CustomEvent } @@ -168,23 +159,21 @@ let providers: EIP6963ProviderDetail[] = [] // across the dapp. export const store = { // Returns the current state of providers. - value: () => providers, + value: ()=> providers, // Subscribes to provider announcements and updates the store accordingly. // Takes a callback function to be invoked on each store update, returning a function to // unsubscribe from the event. - subscribe: (callback: () => void) => { - function onAnnouncement(event: EIP6963AnnounceProviderEvent) { - if (providers.map((p) => p.info.uuid).includes(event.detail.info.uuid)) - return + subscribe: (callback: ()=> void) => { + function onAnnouncement(event: EIP6963AnnounceProviderEvent){ + if(providers.map(p => p.info.uuid).includes(event.detail.info.uuid)) return providers = [...providers, event.detail] callback() } - window.addEventListener("eip6963:announceProvider", onAnnouncement) - window.dispatchEvent(new Event("eip6963:requestProvider")) + window.addEventListener("eip6963:announceProvider", onAnnouncement); + window.dispatchEvent(new Event("eip6963:requestProvider")); - return () => - window.removeEventListener("eip6963:announceProvider", onAnnouncement) - }, + return () => window.removeEventListener("eip6963:announceProvider", onAnnouncement) + } } ``` @@ -198,11 +187,10 @@ the store updates. Create a file `useSyncProviders.ts` in the `hooks` directory with the following code: ```tsx title="useSyncProviders.ts" -import { useSyncExternalStore } from "react" -import { store } from "./store" +import { useSyncExternalStore } from "react"; +import { store } from "./store"; -export const useSyncProviders = () => - useSyncExternalStore(store.subscribe, store.value, store.value) +export const useSyncProviders = ()=> useSyncExternalStore(store.subscribe, store.value, store.value) ``` `useSyncExternalStore` takes three arguments: @@ -222,7 +210,7 @@ when the component unmounts. ### 5. Create connect buttons Create an array of buttons that the user can select to connect to the EIP-6963 wallet providers that -you detect. +you detect. Update `src/App.tsx` to the following: @@ -235,11 +223,12 @@ const App = () => { const handleConnect = async (providerWithInfo: EIP6963ProviderDetail) => { try { - const accounts = (await providerWithInfo.provider.request({ - method: "eth_requestAccounts", - })) as string[] + const accounts = await providerWithInfo.provider.request({ + method: "eth_requestAccounts" + }) as string[] + } catch (error) { - console.error(error) + console.error(error); } } @@ -247,19 +236,17 @@ const App = () => {

Wallets Detected:

- {providers.length > 0 ? ( - providers?.map((provider: EIP6963ProviderDetail) => ( - - )) - ) : ( -
No Announced Wallet Providers
- )} + )) : +
+ No Announced Wallet Providers +
+ }
) @@ -399,7 +386,7 @@ Add the following CSS to `src/App.css` to style the error message: .mmError { height: 36px; padding: 16px; - color: #efefef; + color: #EFEFEF; background-color: transparent; } ``` diff --git a/yarn.lock b/yarn.lock index 5a2c985e001..cc1da083303 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8658,9 +8658,9 @@ __metadata: linkType: hard "fast-loops@npm:^1.1.3": - version: 1.1.3 - resolution: "fast-loops@npm:1.1.3" - checksum: b674378ba2ed8364ca1a00768636e88b22201c8d010fa62a8588a4cace04f90bac46714c13cf638be82b03438d2fe813600da32291fb47297a1bd7fa6cef0cee + version: 1.1.4 + resolution: "fast-loops@npm:1.1.4" + checksum: 8031a20f465ef35ac4ad98258470250636112d34f7e4efcb4ef21f3ced99df95a1ef1f0d6943df729a1e3e12a9df9319f3019df8cc1a0e0ed5a118bd72e505f9 languageName: node linkType: hard