diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72fa40a9563..739a89cb28f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,9 +71,9 @@ To contribute changes: > **Notes:** > - > - All documentation content is located in the `wallet`, `snaps`, `services`, and + > - All documentation content is located in the `wallet`, `sdk`, `snaps`, `services`, and > `developer-tools` directories. - > - If you add a new documentation page, edit `wallet-sidebar.js`, `snaps-sidebar.js`, + > - If you add a new documentation page, edit `wallet-sidebar.js`, `sdk-sidebar.js`, `snaps-sidebar.js`, > `services-sidebar.js`, or `dashboard-sidebar.js` to add the page to the > [sidebar](https://docs-template.consensys.io/create/configure-docusaurus#sidebar). > - If you delete, rename, or move a documentation file, add a @@ -120,7 +120,7 @@ Refer to the [Consensys documentation style guide](https://docs-template.consens ## Add images -All images are located in the `wallet/assets`, `snaps/assets`, `services/images`, and +All images are located in the `wallet/assets`, `sdk/_assets`, `snaps/assets`, `services/images`, and `developer-tools/images` directories. When adding a new image, such as a screenshot or diagram, make sure the image has a white or `#1b1b1d` color background in order for it to be compatible with the site's light and dark modes. diff --git a/docusaurus.config.js b/docusaurus.config.js index 6e49746d33f..30edcc5ad11 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -151,6 +151,17 @@ const config = { } }, ], + [ + "@docusaurus/plugin-content-docs", + { + id: "sdk", + path: "sdk", + routeBasePath: "sdk", + editUrl: "https://github.com/MetaMask/metamask-docs/edit/main/", + sidebarPath: require.resolve("./sdk-sidebar.js"), + breadcrumbs: false, + }, + ], "./src/plugins/plugin-json-rpc.ts", isProd ? [ @@ -178,9 +189,13 @@ const config = { width: 150, }, items: [ + { + to: "sdk", + label: "SDK", + }, { to: "wallet", - label: "Wallet", + label: "Wallet API", }, { to: "snaps", @@ -248,6 +263,10 @@ const config = { label: "Wallet", to: "/wallet", }, + { + label: "SDK", + to: "/sdk", + }, { label: "Snaps", to: "/snaps", diff --git a/sdk-sidebar.js b/sdk-sidebar.js new file mode 100644 index 00000000000..724e7a93ebe --- /dev/null +++ b/sdk-sidebar.js @@ -0,0 +1,68 @@ +// @ts-check + +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const sidebar = { + sdkSidebar: [ + { + type: 'category', + label: 'Introduction', + collapsible: false, + collapsed: false, + items: [ + 'introduction/welcome', + 'introduction/supported-platforms', + 'introduction/supported-networks', + 'introduction/llm-prompt', + { + type: 'link', + label: 'Try Demo App', + href: 'https://metamask-sdk-examples-relink.vercel.app/', + }, + ], + }, + { + type: 'category', + label: 'Quick Start', + collapsible: false, + collapsed: false, + items: [ + 'quick-start/javascript-+-wagmi', + 'quick-start/javascript', + 'quick-start/react-native', + ], + }, + { + type: 'category', + label: 'Guides', + collapsible: false, + collapsed: false, + items: [ + 'guides/user-authentication', + 'guides/network-management', + 'guides/transaction-handling', + 'guides/interact-with-contracts', + { + type: 'category', + label: 'Advanced', + collapsible: true, + collapsed: true, + items: [ + 'guides/advanced/connect-and-sign', + 'guides/advanced/batch-requests', + ], + }, + ], + }, + { + type: 'category', + label: 'API Reference', + collapsible: false, + collapsed: false, + items: [ + 'api-reference/sdk-api' + ], + } + ], +}; + +module.exports = sidebar; diff --git a/sdk/_assets/connect.gif b/sdk/_assets/connect.gif new file mode 100644 index 00000000000..d2f794ce8b6 Binary files /dev/null and b/sdk/_assets/connect.gif differ diff --git a/sdk/_assets/network.gif b/sdk/_assets/network.gif new file mode 100644 index 00000000000..ed597169380 Binary files /dev/null and b/sdk/_assets/network.gif differ diff --git a/sdk/_assets/quickstart.jpg b/sdk/_assets/quickstart.jpg new file mode 100644 index 00000000000..6f023ecb93e Binary files /dev/null and b/sdk/_assets/quickstart.jpg differ diff --git a/sdk/api-reference/sdk-api.md b/sdk/api-reference/sdk-api.md new file mode 100644 index 00000000000..d515c4bb6f4 --- /dev/null +++ b/sdk/api-reference/sdk-api.md @@ -0,0 +1,313 @@ +--- +description: SDK options +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# SDK options + +The [JavaScript version of MetaMask SDK](../connect/metamask-sdk/javascript/index.md) takes the +following options. + +### `checkInstallationImmediately` + + + + +```javascript +checkInstallationImmediately: +``` + + + + +```javascript +checkInstallationImmediately: true +``` + + + + +Enables or disables immediately checking if MetaMask is installed on the user's browser. +If `true`, the SDK checks for installation upon page load and sends a connection request, prompting +the user to install MetaMask if it's not already installed. +If `false`, the SDK waits for the connect method to be called to check for installation. + +The default is `false`. + +### `checkInstallationOnAllCalls` + + + + +```javascript +checkInstallationOnAllCalls: +``` + + + + +```javascript +checkInstallationOnAllCalls: true +``` + + + + +Enables or disables checking if MetaMask is installed on the user's browser before each RPC request. +The default is `false`. + +### `communicationServerUrl` + + + + +```javascript +communicationServerUrl: +``` + + + + +```javascript +communicationServerUrl: "https://metamask-sdk-socket.metafi.codefi.network/" +``` + + + + +The URL of the communication server to use. +This option is mainly used for debugging and testing the SDK. + +### `dappMetadata` + + + + +```javascript +dappMetadata: { + name: , + url: , + iconUrl: , +} +``` + + + + +```javascript +dappMetadata: { + name: "My Dapp", + url: "https://mydapp.com", + iconUrl: "https://mydapp.com/icon.png", +} +``` + + + + +Metadata about the dapp using the SDK. +The metadata options are: + +- `name` - Name of the dapp +- `url` - URL of the dapp +- `iconUrl` - URL of the dapp's icon + +:::tip important +Setting `dappMetaData` creates a clear and trustworthy user experience when connecting your dapp to +MetaMask Mobile. +MetaMask Mobile displays this metadata in the connection modal to help users identify and verify the +connection request. +::: + +### `defaultReadOnlyChainId` + + + + +```javascript +defaultReadOnlyChainId: +``` + + + + +```javascript +defaultReadOnlyChainId: "0x1" +``` + + + + +Enables sending [read-only RPC requests](../how-to/make-read-only-requests.md) to +this chain ID before the user connects to MetaMask. +The value is automatically updated to the chain ID used in MetaMask once connected. + +### `enableAnalytics` + + + + +```javascript +enableAnalytics: +``` + + + + +```javascript +enableAnalytics: true +``` + + + + +Enables or disables sending anonymous analytics to MetaMask to help improve the SDK. +The default is `true`. + +### `extensionOnly` + + + + +```javascript +extensionOnly: +``` + + + + +```javascript +extensionOnly: true +``` + + + + +Enables or disables automatically using the MetaMask browser extension if it's detected. +The default is `true`. + +### `infuraAPIKey` + + + + +```javascript +infuraAPIKey: +``` + + + + +```javascript +infuraAPIKey: process.env.INFURA_API_KEY +``` + + + + +The [Infura API key](/developer-tools/dashboard/get-started/create-api) to +use for RPC requests. +Configure this option to [make read-only RPC requests from your dapp](../how-to/make-read-only-requests.md). + +:::caution important +Use [Infura allowlists](https://docs.infura.io/networks/ethereum/how-to/secure-a-project/use-an-allowlist) +to protect against other people submitting requests to your API key. +You can restrict interactions to specific addresses, origins, user agents, and request methods. +We recommend using all allowlist options to maximize the security of your API key and dapp. +::: + +### `headless` + + + + +```javascript +headless: +``` + + + + +```javascript +headless: true +``` + + + + +Enables or disables headless mode. +Setting this to `true` allows you to [display custom modals](../how-to/display/custom-modals.md). +The default is `false`. + +### `openDeeplink` + + + + +```javascript +openDeeplink: +``` + + + + +```javascript +openDeeplink: (link: string) => { + if (canOpenLink) { + Linking.openURL(link); + } +} +``` + + + + +A function that is called to open a deeplink to the MetaMask Mobile app. + +### `readonlyRPCMap` + + + + +```javascript +readonlyRPCMap: +``` + + + + +```javascript +readonlyRPCMap: { + "0x539": "http://localhost:8545", +} +``` + + + + +A map of RPC URLs to use for [read-only RPC requests](../how-to/make-read-only-requests.md). + +### `shouldShimWeb3` + + + + +```javascript +shouldShimWeb3: +``` + + + + +```javascript +shouldShimWeb3: false +``` + + + + +Enables or disables shimming the `window.web3` object with the Ethereum provider returned by the SDK +(useful for compatibility with older browsers). +The default is `true`. diff --git a/sdk/guides/advanced/batch-requests.md b/sdk/guides/advanced/batch-requests.md new file mode 100644 index 00000000000..312e31f7b38 --- /dev/null +++ b/sdk/guides/advanced/batch-requests.md @@ -0,0 +1,140 @@ +--- +description: Batch multiple JSON-RPC requests using MetaMask SDK. +tags: + - JavaScript SDK +--- + +# Batch Requests + +You can batch multiple JSON-RPC requests using MetaMask SDK. + +:::info + +Check out the [JSON-RPC API](/wallet/reference/json-rpc-methods) reference for more information. + +::: + +The SDK's `metamask_batch` method enables you to batch multiple JSON-RPC requests in a single call, +providing a streamlined approach for dapps to interact with EVM networks, and enabling complex +sequences of actions. +This method enhances performance, usability, and efficiency by reducing the number of network calls +made to MetaMask. + +Use cases include: + +- **Batching multiple signatures** - Send multiple signing requests in one batch. + +- **Switching networks** - Switch the EVM network, perform an action such as sending a transaction, + and switch back, all in one batch. + +- **Mixed transactions and signatures** - Combine transaction sending and signing requests in one batch. + +`metamask_batch` opens up additional possibilities for sophisticated transaction flows in dapps, +enhancing the user experience and operational efficiency. + +## Prerequisites + +Set up MetaMask SDK in your JavaScript dapp. + +## Use the `metamask_batch` method + +`metamask_batch` takes an array of JSON-RPC requests (`ChainRPC[]`) as its parameter. + +Each request in the batch is independent. +The user receives a prompt for each action within the batch, allowing them to approve or reject +individual requests. +If any request is rejected, the entire batch fails and an error is returned, ensuring integrity in +transactional operations. + +The method returns an array of results corresponding to each request. + +### React / Next.js / React Native example + +The following is an example of using `metamask_batch` to batch +[`personal_sign`](/wallet/reference/json-rpc-methods/personal_sign) and +[`eth_sendTransaction`](/wallet/reference/json-rpc-methods/eth_sendtransaction) in React, Next.js, or React Native/Expo: + +```javascript title="index.js" +import { metamask_batch } from "metamask-sdk" + +function MyComponent() { + const handleBatchRequest = async () => { + const batchRequests = [ + { method: "personal_sign", params: ["message", "address"] }, + { + method: "eth_sendTransaction", + params: [ + { + /* Transaction parameters */ + }, + ], + }, + ] + + try { + const results = await metamask_batch(batchRequests) + console.log(results) // Process results. + } catch (error) { + console.error("Batch request failed", error) + } + } + + return +} +``` + +### Vue.js example + +The following is an example of using `metamask_batch` to batch +[`personal_sign`](/wallet/reference/json-rpc-methods/personal_sign) and +[`eth_sendTransaction`](/wallet/reference/json-rpc-methods/eth_sendtransaction) in Vue.js: + +```javascript title="App.vue" + +``` + +### Best practices + +Follow these guidelines when using `metamask_batch`: + +- **Ensure each request in the batch is properly formatted** according to the JSON-RPC specifications. + +- **Handle errors appropriately**, especially when a batch request is partially approved. + +- **Test batch operations** to ensure consistent behavior across different networks and accounts. + +- **Be aware of the dependencies between chained requests.** + Avoid creating a dependency where the outcome of one request directly influences the context or + validity of a subsequent request within the same batch. + For example, avoid chaining a [`wallet_switchEthereumChain`](/wallet/reference/json-rpc-methods/wallet_switchethereumchain) + request with [`eth_signTypedData_v4`](/wallet/reference/json-rpc-methods/eth_signtypeddata_v4), because + `eth_signTypedData_v4` relies on the current chain ID, which would be altered by `wallet_switchEthereumChain`. + This approach ensures that each request in the batch operates independently and maintains its + integrity, regardless of changes introduced by preceding requests in the batch. diff --git a/sdk/guides/advanced/connect-and-sign.md b/sdk/guides/advanced/connect-and-sign.md new file mode 100644 index 00000000000..f1b4d4d173a --- /dev/null +++ b/sdk/guides/advanced/connect-and-sign.md @@ -0,0 +1,108 @@ +--- +description: Use MetaMask SDK to connect and sign in a single interaction. +tags: + - JavaScript SDK + - iOS SDK +--- + +# Connect and Sign + +You can connect to MetaMask and sign data in a single interaction from your JavaScript, iOS, +Android. + +The SDK's `connectAndSign` method provides a streamlined approach for dapps to interact with MetaMask. +This method combines the [`eth_requestAccounts`] and [`personal_sign`] RPC methods, executing them sequentially. +`connectAndSign` takes one parameter, the message string to be signed, and passes the message and +the output of [`eth_requestAccounts`] directly to [`personal_sign`]. + +:::info + +Check out the [JSON-RPC API](/wallet/reference/json-rpc-methods) reference for more information. + +::: + +This method enhances dapp user experience, especially on mobile platforms, by allowing users to +connect to MetaMask and sign a message in a single interaction, requiring only one switch between +the mobile dapp and MetaMask Mobile. +This is useful for various purposes such as authentication and transaction verification. + +

+ +

+ +## Prerequisites + +- MetaMask SDK set up in your JavaScript dapp. + +- MetaMask Mobile version 7.10 or later. + Your users must have an updated version of MetaMask Mobile for this feature to work correctly. + For older versions of MetaMask, this function may not work as expected. + +## Use the `connectAndSign` method + +Use the `connectAndSign` method as follows: + +```javascript +const connectAndSign = async () => { + try { + const signResult = await sdk?.connectAndSign({ + msg: "Connect + Sign message", + }) + setResponse(signResult) + } catch (err) { + console.warn("failed to connect..", err) + } +} +``` + +To invoke `connectAndSign`: + +1. Ensure the `MetaMaskSDK` instance (`sdk` in this context) is properly initialized and available. +2. Call `connectAndSign` with the message to be signed. +3. Handle the promise to process the response or catch any errors. + +## Examples + +The following is an example of using the `connectAndSign` method in a React dapp, integrating it +into a functional component: + +```javascript +import React, { useState } from "react" +import { useSDK } from "@metamask/sdk-react" + +function MyComponent() { + 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) + } catch (error) { + console.error("Error in signing:", error) + } + } + + return ( +
+ + {signedMessage &&

Signed Message: {signedMessage}

} +
+ ) +} +``` + +For a comprehensive React example, see the `App.tsx` file of the example React dapp. + +For examples of using the `connectAndSign` function in Next.js and Vue.js, see the +[example Next.js dapp](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/nextjs-demo) +and [example Vue.js dapp](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/vuejs) +in the JavaScript SDK GitHub repository. + + + +[`eth_requestAccounts`]: /wallet/reference/json-rpc-methods/eth_requestAccounts +[`personal_sign`]: /wallet/reference/json-rpc-methods/personal_sign diff --git a/sdk/guides/interact-with-contracts.md b/sdk/guides/interact-with-contracts.md new file mode 100644 index 00000000000..759510577e7 --- /dev/null +++ b/sdk/guides/interact-with-contracts.md @@ -0,0 +1,294 @@ +--- +description: Contract Interactions +--- + +# Contract Interactions + +This guide covers everything you need to know about interacting with smart contracts using the MetaMask SDK. You'll learn how to: +- **Read data** from smart contracts +- **Write data** to smart contracts +- **Handle contract events** +- **Manage transaction states** +- **Handle contract errors** + +We provide implementations using both **Wagmi** (recommended) and **vanilla JavaScript**. + +### Using Wagmi + +Wagmi provides dedicated hooks for contract interactions, making it simple to read and write contract data: + +#### Reading Contract Data + +```tsx +import { useReadContract } from 'wagmi' + +function TokenBalance() { + const { + data: balance, + isError, + isLoading + } = useReadContract({ + address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', + abi: [ + { + name: 'balanceOf', + type: 'function', + stateMutability: 'view', + inputs: [{ name: 'owner', type: 'address' }], + outputs: [{ name: 'balance', type: 'uint256' }], + }, + ], + functionName: 'balanceOf', + args: ['0x03A71968491d55603FFe1b11A9e23eF013f75bCF'], + }) + + if (isLoading) return
Loading balance...
+ if (isError) return
Error fetching balance
+ + return
Balance: {balance?.toString()}
+} +``` + +#### Writing to Contracts + +```tsx +import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi' + +function MintNFT() { + const { + writeContract, + data: hash, + error, + isPending + } = useWriteContract() + + const { + isLoading: isConfirming, + isSuccess: isConfirmed + } = useWaitForTransactionReceipt({ + hash + }) + + function mint() { + writeContract({ + address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', + abi: [ + { + name: 'mint', + type: 'function', + stateMutability: 'nonpayable', + inputs: [{ name: 'tokenId', type: 'uint256' }], + outputs: [], + }, + ], + functionName: 'mint', + args: [123n], // Token ID + }) + } + + return ( +
+ + + {hash && ( +
+ Transaction Hash: {hash} + {isConfirming &&
Waiting for confirmation...
} + {isConfirmed &&
NFT Minted Successfully!
} +
+ )} + + {error &&
Error: {error.message}
} +
+ ) +} +``` + +### Using Vanilla JavaScript + +For non-React applications, here's how to implement contract interactions using vanilla JavaScript: + +:::info + +Check out the [Provider API](/wallet/reference/provider-api) reference and [JSON-RPC API](/wallet/reference/json-rpc-methods) reference for more information. + +::: + +#### Initialize MetaMask SDK + +```javascript +import MetaMaskSDK from '@metamask/sdk'; + +const MMSDK = new MetaMaskSDK(); +const ethereum = MMSDK.getProvider(); +``` + +#### Reading Contract Data + +```javascript +async function getBalance(contractAddress, userAddress) { + try { + // Create function signature for balanceOf(address) + const functionSignature = '0x70a08231'; + // Pad address to 32 bytes + const encodedAddress = userAddress.slice(2).padStart(64, '0'); + + const result = await ethereum.request({ + method: 'eth_call', + params: [{ + to: contractAddress, + data: functionSignature + encodedAddress, + }], + }); + + return BigInt(result); + } catch (error) { + console.error('Error reading balance:', error); + throw error; + } +} + +// Example usage +async function displayBalance() { + const status = document.getElementById('status'); + try { + const balance = await getBalance( + '0xContractAddress', + '0xUserAddress' + ); + status.textContent = `Balance: ${balance.toString()}`; + } catch (error) { + status.textContent = `Error: ${error.message}`; + } +} +``` + +#### Writing to Contracts + +```javascript +async function mintNFT(contractAddress, tokenId) { + try { + // Get user's account + const accounts = await ethereum.request({ + method: 'eth_requestAccounts' + }); + + // Create function signature for mint(uint256) + const functionSignature = '0x6a627842'; + // Pad tokenId to 32 bytes + const encodedTokenId = tokenId.toString(16).padStart(64, '0'); + + // Send transaction + const txHash = await ethereum.request({ + method: 'eth_sendTransaction', + params: [{ + from: accounts[0], + to: contractAddress, + data: functionSignature + encodedTokenId, + }], + }); + + return txHash; + } catch (error) { + if (error.code === 4001) { + throw new Error('Transaction rejected by user'); + } + throw error; + } +} + +// Track transaction status +async function watchTransaction(txHash) { + return new Promise((resolve, reject) => { + const checkTransaction = async () => { + try { + const tx = await ethereum.request({ + method: 'eth_getTransactionReceipt', + params: [txHash], + }); + + if (tx) { + if (tx.status === '0x1') { + resolve(tx); + } else { + reject(new Error('Transaction failed')); + } + } else { + setTimeout(checkTransaction, 2000); + } + } catch (error) { + reject(error); + } + }; + + checkTransaction(); + }); +} +``` + +#### Example Implementation + +```html +
+ +
+
+ + +``` + +### Best Practices + +1. **Contract Validation** + - Always **verify contract addresses** + - Double-check **ABI correctness** + - **Validate input data** before sending + - Use **typed data** when possible (for example by using [viem](https://viem.sh/)) + +2. **Error Handling** + - Handle common errors like **user rejection** and **contract reverts** + - Provide **clear error messages** to users + - Implement proper **error recovery** flows + - Consider **gas estimation failures** + +3. **User Experience** + - Show **clear loading states** + - Display **transaction progress** + - Provide **confirmation feedback** + - Enable proper **error recovery** + +### Common Errors + +| Error Code | Description | Solution | +|------------|-------------|----------| +| **4001** | User rejected transaction | Show clear message and retry option | +| **-32000** | Invalid input | Validate input data before sending | +| **-32603** | Contract execution reverted | Check contract conditions and handle gracefully | +| **-32002** | Request already pending | Prevent multiple concurrent transactions | + +### Next Steps + +- [User Authentication](/sdk/guides/user-authentication) +- [Network Management](/sdk/guides/network-management) +- [Transaction Handling](/sdk/guides/transaction-handling) \ No newline at end of file diff --git a/sdk/guides/network-management.md b/sdk/guides/network-management.md new file mode 100644 index 00000000000..2c5ac9ef241 --- /dev/null +++ b/sdk/guides/network-management.md @@ -0,0 +1,230 @@ +--- +description: Network Management +--- + +# Network Management + +This guide covers everything you need to know about managing networks in your dApp using the MetaMask SDK. +We provide implementations using both **Wagmi** (recommended) and **vanilla JavaScript**. + +
+
+ + Switch Networks + +
+
+ +
+
+ +### Using Wagmi + +Wagmi provides intuitive hooks for all network-related operations, making chain management straightforward in React applications. + +#### Detect Current Network + +```tsx +import { useChainId, useChains } from 'wagmi' + +function NetworkStatus() { + const chainId = useChainId() + const chains = useChains() + + const currentChain = chains.find(c => c.id === chainId) + + if (!currentChain) { + return
Not connected to any network
+ } + + return ( +
+
Connected to {currentChain.name}
+
Chain ID: {chainId}
+
Supported chains: {chains.map(c => c.name).join(', ')}
+
+ ) +} +``` + +#### Switch Networks + +```tsx +import { useSwitchChain } from 'wagmi' + +function NetworkSwitcher() { + const { chains, switchChain } = useSwitchChain() + + return ( +
+ {chains.map((chain) => ( + + ))} +
+ ) +} +``` + +#### Handle Network Changes + +```tsx +import { useChainId } from 'wagmi' +import { useEffect } from 'react' + +function NetworkWatcher() { + const chainId = useChainId() + + useEffect(() => { + console.log('Chain ID changed:', chainId) + }, [chainId]) + + return null +} +``` + +### Using Vanilla JavaScript + +For non-React applications, here's how to implement network management using vanilla JavaScript: + +:::info + +Check out the [Provider API](/wallet/reference/provider-api) reference and [JSON-RPC API](/wallet/reference/json-rpc-methods) reference for more information. + +::: + +#### Initialize MetaMask SDK + +```javascript +import MetaMaskSDK from '@metamask/sdk'; + +const MMSDK = new MetaMaskSDK(); +const ethereum = MMSDK.getProvider(); +``` + +#### Detect Current Network + +```javascript +// Get current chain ID +async function getCurrentChain() { + try { + const chainId = await ethereum.request({ + method: 'eth_chainId' + }); + console.log('Current chain ID:', chainId); + return chainId; + } catch (err) { + console.error('Error getting chain:', err); + } +} + +// Listen for network changes +ethereum.on('chainChanged', (chainId) => { + console.log('Network changed to:', chainId); + // We recommend reloading the page + window.location.reload(); +}); +``` + +#### Switch Networks + +```javascript +// Network configurations +const networks = { + mainnet: { + chainId: '0x1', + name: 'Ethereum Mainnet' + }, + optimism: { + chainId: '0xA', + name: 'Optimism', + rpcUrls: ['https://mainnet.optimism.io'], + nativeCurrency: { + name: 'Ethereum', + symbol: 'ETH', + decimals: 18 + }, + blockExplorerUrls: ['https://optimistic.etherscan.io'] + } +}; + +async function switchNetwork(networkKey) { + const network = networks[networkKey]; + + try { + // Try to switch to the network + await ethereum.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: network.chainId }] + }); + } catch (err) { + // If the error code is 4902, the network needs to be added + if (err.code === 4902) { + try { + await ethereum.request({ + method: 'wallet_addEthereumChain', + params: [{ + chainId: network.chainId, + chainName: network.name, + rpcUrls: network.rpcUrls, + nativeCurrency: network.nativeCurrency, + blockExplorerUrls: network.blockExplorerUrls + }] + }); + } catch (addError) { + console.error('Error adding network:', addError); + } + } else { + console.error('Error switching network:', err); + } + } +} +``` + +#### Example HTML Implementation + +```html +
+
Current Network: Loading...
+ + +
+``` + + + +### Best Practices + +1. **Error Handling** + - Implement error handling for network switching operations + - Provide **clear feedback messages** to users when network operations fail + - Handle cases where networks need to be **added before switching** + +2. **User Experience** + - Display **loading states** during network switches + - Show **clear network status information** at all times + - Consider **warning users** before initiating network switches + - Use an **RPC provider** that supports your target networks + +### Common Errors + +| Error Code | Description | Solution | +|------------|-------------|----------| +| **4902** | Network not added | Use `wallet_addEthereumChain` to add the network first | +| **4001** | User rejected request | Show a message asking user to approve the network switch | +| **-32002** | Request already pending | Disable network switch button while request is pending | + +### Next Steps + +- [User Authentication](/sdk/guides/user-authentication) +- [Transaction Handling](/sdk/guides/transaction-handling) +- [Interact with Contracts](/sdk/guides/interact-with-contracts) \ No newline at end of file diff --git a/sdk/guides/transaction-handling.md b/sdk/guides/transaction-handling.md new file mode 100644 index 00000000000..b9efc48c2f4 --- /dev/null +++ b/sdk/guides/transaction-handling.md @@ -0,0 +1,270 @@ +--- +description: Transaction Handling +--- + +# Transaction Handling + +This guide covers everything you need to know about handling Ethereum (and EVM) transactions with the MetaMask SDK. You'll learn how to: +- **Send transactions** +- **Track transaction status** in real-time +- **Estimate gas costs** accurately +- **Handle transaction errors** gracefully +- **Manage complex transaction patterns** + +We provide implementations using both **Wagmi** (recommended) and **vanilla JavaScript**. + +### Using Wagmi + +Wagmi provides hooks for sending transactions and tracking their status: + +#### Basic Transaction + +```tsx +import { parseEther } from 'viem' +import { useSendTransaction, useWaitForTransactionReceipt } from 'wagmi' + +function SendTransaction() { + const { + data: hash, + error, + isPending, + sendTransaction + } = useSendTransaction() + + const { + isLoading: isConfirming, + isSuccess: isConfirmed + } = useWaitForTransactionReceipt({ + hash + }) + + async function handleSend() { + sendTransaction({ + to: '0x...', + value: parseEther('0.1') // 0.1 ETH + }) + } + + return ( +
+ + + {hash && ( +
+ Transaction Hash: {hash} + {isConfirming &&
Waiting for confirmation...
} + {isConfirmed &&
Transaction confirmed!
} +
+ )} + + {error &&
Error: {error.message}
} +
+ ) +} +``` + +#### Advanced Transaction with Gas Estimation + +```tsx +import { parseEther } from 'viem' +import { + useSendTransaction, + useWaitForTransactionReceipt, + useEstimateGas +} from 'wagmi' + +function AdvancedTransaction() { + const transaction = { + to: '0x...', + value: parseEther('0.1'), + data: '0x...' // Optional contract interaction data + } + + // Estimate gas + const { data: gasEstimate } = useEstimateGas(transaction) + + const { sendTransaction } = useSendTransaction({ + ...transaction, + gas: gasEstimate, + onSuccess: (hash) => { + console.log('Transaction sent:', hash) + } + }) + + return +} +``` + +### Using Vanilla JavaScript + +For non-React applications, here's how to implement transaction handling using vanilla JavaScript: + +:::info + +Check out the [Provider API](/wallet/reference/provider-api) reference and [JSON-RPC API](/wallet/reference/json-rpc-methods) reference for more information. + +::: + +#### Initialize MetaMask SDK + +```javascript +import MetaMaskSDK from '@metamask/sdk'; + +const MMSDK = new MetaMaskSDK(); +const ethereum = MMSDK.getProvider(); +``` + +#### Basic Transaction + +```javascript +async function sendTransaction(recipientAddress, amount) { + try { + // Get current account + const accounts = await ethereum.request({ + method: 'eth_requestAccounts' + }); + const from = accounts[0]; + + // Convert ETH amount to Wei (hex) + const value = `0x${(amount * 1e18).toString(16)}`; + + // Prepare transaction + const transaction = { + from, + to: recipientAddress, + value, + // Gas fields are optional - MetaMask will estimate + }; + + // Send transaction + const txHash = await ethereum.request({ + method: 'eth_sendTransaction', + params: [transaction], + }); + + return txHash; + } catch (error) { + if (error.code === 4001) { + throw new Error('Transaction rejected by user'); + } + throw error; + } +} + +// Track transaction status +function watchTransaction(txHash) { + return new Promise((resolve, reject) => { + const checkTransaction = async () => { + try { + const tx = await ethereum.request({ + method: 'eth_getTransactionReceipt', + params: [txHash], + }); + + if (tx) { + if (tx.status === '0x1') { + resolve(tx); + } else { + reject(new Error('Transaction failed')); + } + } else { + setTimeout(checkTransaction, 2000); // Check every 2 seconds + } + } catch (error) { + reject(error); + } + }; + + checkTransaction(); + }); +} +``` + +#### Example Implementation + +```html +
+ + + +
+
+ + +``` + +#### Gas Estimation + +```javascript +async function estimateGas(transaction) { + try { + const gasEstimate = await ethereum.request({ + method: 'eth_estimateGas', + params: [transaction] + }); + + // Add 20% buffer for safety + return BigInt(gasEstimate) * 120n / 100n; + } catch (error) { + console.error('Gas estimation failed:', error); + throw error; + } +} +``` + +### Best Practices + +1. **Transaction Security** + - Always **validate inputs** before sending transactions + - Check wallet balances to **ensure sufficient** funds + - **Verify addresses** are valid + +2. **Error Handling** + - Handle common errors like **user rejection** and **insufficient funds** + - Provide **clear error messages** to users + - Implement proper **error recovery** flows + - Consider **network congestion** in gas estimates + +3. **User Experience** + - Display **clear loading states** during transactions + - Show **transaction progress** in real-time + - Provide **detailed transaction information** + +### Common Errors + +| Error Code | Description | Solution | +|------------|-------------|----------| +| **4001** | User rejected transaction | Show retry option and clear error message | +| **-32603** | Insufficient funds | Check balance before sending transaction | +| **-32000** | Gas too low | Increase gas limit or add buffer to estimation | +| **-32002** | Request already pending | Prevent multiple concurrent transactions | + +### Next Steps + +- [User Authentication](/sdk/guides/user-authentication) +- [Network Management](/sdk/guides/network-management) +- [Interact with Contracts](/sdk/guides/interact-with-contracts) \ No newline at end of file diff --git a/sdk/guides/user-authentication.md b/sdk/guides/user-authentication.md new file mode 100644 index 00000000000..7f24c14ac84 --- /dev/null +++ b/sdk/guides/user-authentication.md @@ -0,0 +1,196 @@ +--- +description: User Authentication +--- + +# User Authentication + +Connect and manage user wallet sessions in your dApp. This guide covers both **Wagmi** (recommended) and **vanilla JavaScript** approaches. + +
+
+ + Connect to MetaMask + +
+
+ +
+
+ + +### Using Wagmi + +Wagmi provides a simple, hook-based approach for handling wallet connections: + +```tsx +import { useAccount, useConnect, useDisconnect } from 'wagmi' + +function ConnectWallet() { + const { address, isConnected } = useAccount() + const { connectors, connect, isPending } = useConnect() + const { disconnect } = useDisconnect() + + if (isConnected) { + return ( +
+
Connected to {address}
+ +
+ ) + } + + return ( +
+ {connectors.map((connector) => ( + + ))} +
+ ) +} +``` + +#### Handle Account Changes + +Wagmi provides a dedicated hook for handling account lifecycle events: + +```tsx +import { useAccountEffect } from 'wagmi' + +function WatchAccount() { + useAccountEffect({ + onConnect(data) { + console.log('Connected!', { + address: data.address, + chainId: data.chainId, + isReconnected: data.isReconnected + }) + }, + onDisconnect() { + console.log('Disconnected!') + } + }) + + return
Watching for account changes...
+} +``` + +### Using Vanilla JavaScript + +If you're not using React, here's how to implement authentication directly: + +```javascript +import { MetaMaskSDK } from '@metamask/sdk'; + +// Initialize SDK +const MMSDK = new MetaMaskSDK(); +const provider = MMSDK.getProvider(); + +// Connect wallet +async function connectWallet() { + try { + // Disable button while request is pending + document.getElementById('connectBtn').disabled = true; + + const accounts = await provider.request({ + method: 'eth_requestAccounts' + }); + + const account = accounts[0]; + console.log('Connected:', account); + + // Update UI + document.getElementById('status').textContent = `Connected: ${account}`; + document.getElementById('connectBtn').style.display = 'none'; + document.getElementById('disconnectBtn').style.display = 'block'; + } catch (err) { + if (err.code === 4001) { + console.log('User rejected connection'); + } else { + console.error(err); + } + } finally { + document.getElementById('connectBtn').disabled = false; + } +} + +// Handle account changes +provider.on('accountsChanged', (accounts) => { + if (accounts.length === 0) { + // User disconnected + document.getElementById('status').textContent = 'Not connected'; + document.getElementById('connectBtn').style.display = 'block'; + document.getElementById('disconnectBtn').style.display = 'none'; + } else { + // Account changed + document.getElementById('status').textContent = `Connected: ${accounts[0]}`; + } +}); +``` + +:::info + +Check out the [Provider API](/wallet/reference/provider-api) reference for more information. + +::: + +#### HTML + +```html +
+
Not connected
+ + +
+``` + +### Best Practices + +1. **User Interaction** + - Only trigger connection requests in response to user actions (like button clicks) + - Never auto-connect on page load + - Provide clear feedback during connection states + +2. **Error Handling** + - Handle common errors like user rejection (code 4001) + - Provide clear error messages to users + - Fallback gracefully when MetaMask is not installed + +3. **Account Changes** + - Always listen for account changes + - Update your UI when accounts change + - Handle disconnection events + +4. **Chain Support** + - Listen for network/chain changes + - Verify the current chain meets your requirements + - Provide clear messaging when users need to switch networks + - Learn more here: [Network Management](/sdk/guides/network-management) + +### Common Errors + +| Error Code | Description | Solution | +|------------|-------------|----------| +| **4001** | User rejected request | Show a message asking user to approve the connection | +| **-32002** | Request already pending | Disable connect button while request is pending | +| **-32603** | Internal JSON-RPC error | Check if MetaMask is properly installed | + +### Next Steps + +- [Network Management](/sdk/guides/network-management) +- [Transaction Handling](/sdk/guides/transaction-handling) +- [Interact with Contracts](/sdk/guides/interact-with-contracts) \ No newline at end of file diff --git a/sdk/introduction/llm-prompt.md b/sdk/introduction/llm-prompt.md new file mode 100644 index 00000000000..12f7c136fac --- /dev/null +++ b/sdk/introduction/llm-prompt.md @@ -0,0 +1,121 @@ +--- +description: LLM Prompt +--- + +# LLM prompt + +The following text is a condensed introduction to the MetaMask SDK, for use in an LLM's limited context. + +Go ahead, copy and paste it into an LLM-based chatbot and see how it works! + +``` +You are a helpful assistant with expertise in MetaMask SDK integration. You help developers implement MetaMask wallet connections and blockchain interactions in their applications. + +Core Capabilities: +- Connect to MetaMask wallet (extension or mobile) +- Read and write data to smart contracts +- Handle blockchain transactions +- Manage network connections +- Work with Web3 standards (EIP-1193, EIP-6963) + +Technologies: +Primary stack (recommended): +- Wagmi (React hooks for Ethereum) +- TypeScript +- React/Next.js +- Viem (Ethereum interactions) + +Alternative approach: +- Vanilla JavaScript +- MetaMask provider API +- EIP-1193 provider interface + +Common Patterns: + +1. Wallet Connection + +Using Wagmi (Recommended): + import { useConnect } from 'wagmi' + + function Connect() { + const { connect, connectors } = useConnect() + return ( + + ) + } + +Using Vanilla JS: + const provider = window.ethereum; + const accounts = await provider.request({ + method: 'eth_requestAccounts' + }); + +2. Reading Contract Data + +Using Wagmi: + const { data } = useReadContract({ + address: contractAddress, + abi: contractABI, + functionName: 'balanceOf', + args: [address], + }) + +Using Vanilla JS: + const result = await provider.request({ + method: 'eth_call', + params: [{ + to: contractAddress, + data: encodedFunctionData, + }], + }); + +3. Writing to Contracts + +Using Wagmi: + const { writeContract } = useWriteContract(); + await writeContract({ + address: contractAddress, + abi: contractABI, + functionName: 'mint', + args: [tokenId], + }) + +Using Vanilla JS: + await provider.request({ + method: 'eth_sendTransaction', + params: [{ + to: contractAddress, + data: encodedFunctionData, + }], + }); + +Best Practices: +1. Always handle errors gracefully +2. Show clear loading states +3. Track transaction status +4. Validate inputs and addresses +5. Use appropriate gas settings +6. Consider mobile wallet interactions + +Response Guidelines: +When answering questions: +1. Prefer Wagmi examples unless vanilla JS is specifically requested +2. Include error handling in examples +3. Consider both web and mobile wallet scenarios +4. Provide TypeScript types where relevant +5. Include brief explanations with code examples +6. Consider security implications + +Example Usage: +You can ask questions like: +- "How do I connect to MetaMask?" +- "How do I read a token balance?" +- "How do I send a transaction?" +- "How do I handle network changes?" +- "How do I implement wallet disconnection?" +- "How do I add error handling for contract calls?" + +Feel free to ask about specific implementation details, best practices, or troubleshooting. +``` \ No newline at end of file diff --git a/sdk/introduction/supported-networks.md b/sdk/introduction/supported-networks.md new file mode 100644 index 00000000000..af9d3de8343 --- /dev/null +++ b/sdk/introduction/supported-networks.md @@ -0,0 +1,30 @@ +--- +description: Supported networks +--- + +# Supported networks + +## EVM networks + +MetaMask SDK works with all EVM-compatible L1/L2 networks: + +- Ethereum +- Linea +- Base +- Optimism +- Polygon +- Arbitrum +- Avalanche +- BNB Chain +- and [many more](https://chainlist.org/) + +:::tip +For production deployments, it's important to use reliable RPC providers instead of public nodes. We recommend using services like [Infura](https://infura.io/) to ensure better reliability and performance. +::: + +## Non-EVM networks + +Some non-EVM networks can work as well via [MetaMask Snaps](https://metamask.io/snaps/). + +- Starknet ([learn more here](https://docs.metamask.io/wallet/how-to/use-non-evm-networks/starknet/)) + diff --git a/sdk/introduction/supported-platforms.md b/sdk/introduction/supported-platforms.md new file mode 100644 index 00000000000..40c7a264ebb --- /dev/null +++ b/sdk/introduction/supported-platforms.md @@ -0,0 +1,26 @@ +--- +description: Supported platforms +--- + +# Supported platforms + +MetaMask SDK lets you connect your apps to MetaMask Wallet in the following ways: + +- **Desktop web**: Automatically connects to Wallet extension or Wallet mobile app via QR code. + +- **Mobile**: Wallet SDK generates a deep link that takes users straight to the Wallet mobile app. + +| Dapp Location | User Device | Connection Method | Metamask SDK | Other SDKs | +|---------------|-------------|------------------|--------------------------|--------------------------| +| Desktop Web | Wallet Extension | Automatic connection via browser extension | Supported | Supported | +| Desktop Web | Wallet Mobile App | QR code scan with mobile wallet | Supported | Limited | +| Mobile Browser | Wallet Mobile App | Deep link directly to mobile wallet app | Supported | Limited | +| Mobile App | Wallet Mobile App | Deep link directly to mobile wallet app | Supported | Limited | + +
+ +:::tip + +For better user experience on **mobile**, it's important to use reliable RPC providers instead of public nodes. We recommend using services like [Infura](https://infura.io/) to ensure better reliability and performance. + +::: diff --git a/sdk/introduction/welcome.md b/sdk/introduction/welcome.md new file mode 100644 index 00000000000..3178a5a4aaa --- /dev/null +++ b/sdk/introduction/welcome.md @@ -0,0 +1,31 @@ +--- +slug: / +description: Welcome +--- + +# Welcome + +Welcome to the **MetaMask SDK** developer documentation! + +MetaMask SDK is a **toolkit that allows you to build onchain apps** by: + +- Authenticating users +- Managing wallet states +- Handling transactions +- Interacting with contracts +- and many more! + +### Why use the SDK? + +- Works on multiple platforms + - Web - via browser extensions or QR codes for the mobile app + - Mobile - via deep links to the mobile app +- Works with all EVM-compatible L1/L2 networks +- Handles onboarding of users +- Battle tested with millions of users on MetaMask + +### Where do I start? + +- [Install SDK - JavaScript + Wagmi](/sdk/quick-start/javascript-+-wagmi) +- [Install SDK - JavaScript](/sdk/quick-start/javascript) +- [Install SDK - React Native](/sdk/quick-start/react-native) diff --git a/sdk/quick-start/javascript-+-wagmi.md b/sdk/quick-start/javascript-+-wagmi.md new file mode 100644 index 00000000000..82bca4f84d9 --- /dev/null +++ b/sdk/quick-start/javascript-+-wagmi.md @@ -0,0 +1,172 @@ +--- +description: JavaScript + Wagmi (recommended) +--- + +# JavaScript + Wagmi (recommended) + +Get started with MetaMask SDK in your web application. + +This quickstart app demonstrates how to integrate the MetaMask SDK with a [Next.js](https://nextjs.org/) application using [wagmi](https://wagmi.sh/). + +
+ +
+
+ + Quickstart + +
+
+

Features

+ +
+
+ +### Setup via template + +Download directly from our examples repository: +```bash +git clone https://github.com/metamask/metamask-sdk-examples.git +``` + +Change directory to the quickstart example: +```bash +cd metamask-sdk-examples/examples/quickstart/ +``` + +Install dependencies: +```bash +pnpm install +``` + +Run the project: +```bash +pnpm dev +``` + +Congratulations! You've successfully set up the MetaMask SDK with wagmi. Now it's time to add your own functionality. + +### Manual setup + +#### Installation + +Install MetaMask SDK along with its peer dependencies to an existing React project: + +```bash +pnpm install @metamask/sdk wagmi viem@2.x @tanstack/react-query +``` + +#### Import required dependencies + +Go to the root of your project and import the required dependencies: + +```jsx +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { http, WagmiProvider, createConfig } from 'wagmi'; +import { mainnet, linea, lineaSepolia } from "wagmi/chains"; +import { metaMask } from 'wagmi/connectors'; +``` + +#### Configure + +Set up your configuration with desired chains and connectors. + +```jsx +const config = createConfig({ + ssr: true, // make sure to enable this for server-side rendering (SSR) applications + chains: [mainnet, linea, lineaSepolia], + connectors: [metaMask()], + transports: { + [mainnet.id]: http(), + [linea.id]: http(), + [lineaSepolia.id]: http(), + }, +}); +``` + +#### Set up providers + +Wrap your application with the necessary providers: + +```jsx +const client = new QueryClient(); + +const App = () => { + return ( + + + + + + ); +} +``` + +#### Add the connect button + +Add the wallet connect and disconnect buttons to your application: + +```jsx +import { useAccount, useConnect, useDisconnect } from 'wagmi' + +export const ConnectButton = () => { + const { address } = useAccount() + const { connectors, connect } = useConnect() + const { disconnect } = useDisconnect() + + return ( +
+ {address ? ( + + ) : ( + connectors.map((connector) => ( + + )) + )} +
+ ) +} +``` + +Once you've added the connect button, you can test your app by running `npm run dev` or `pnpm run dev` or `yarn dev`. +It should work with the [extension](https://metamask.io/download/) installed or the [mobile app](https://metamask.io/download/). + +### Production readiness + +:::tip +For production deployments, it's important to use reliable RPC providers instead of public nodes. We recommend using services like [Infura](https://infura.io/) to ensure better reliability and performance. +::: + +This is how you can configure your RPC endpoints via the Wagmi config: + +```jsx +const config = createConfig({ + // ... other config options + transports: { + [mainnet.id]: http("https://mainnet.infura.io/v3/YOUR-API-KEY"), + [sepolia.id]: http("https://sepolia.infura.io/v3/YOUR-API-KEY"), + }, +}); +``` + +Sign up [here](https://infura.io/) to Infura for a free account and get your API key. + +### Add your own functionality + +Now that you have the basic setup complete, check out these guides to add your own functionality: + +- [User authentication](/sdk/guides/user-authentication) +- [Network management](/sdk/guides/network-management) +- [Transaction handling](/sdk/guides/transaction-handling) +- [Smart contract interactions](/sdk/guides/interact-with-contracts) + +### More examples + +Check out our example repository for more [metamask-sdk-examples](https://github.com/metamask/metamask-sdk-examples) diff --git a/sdk/quick-start/javascript.md b/sdk/quick-start/javascript.md new file mode 100644 index 00000000000..63a9cdf2574 --- /dev/null +++ b/sdk/quick-start/javascript.md @@ -0,0 +1,135 @@ +--- +description: JavaScript +--- + +# JavaScript + +This guide covers setting up MetaMask SDK in JavaScript applications. The SDK enables your users to easily connect to MetaMask extension and mobile app across different JavaScript environments. + +### Prerequisites + +- MetaMask Mobile v5.8.1+ +- npm or yarn installed + +### Installation + +```bash +npm install @metamask/sdk +# or +yarn add @metamask/sdk +``` + +### Basic Usage + +#### Web Applications + +```javascript +import { MetaMaskSDK } from "@metamask/sdk" + +const MMSDK = new MetaMaskSDK({ + dappMetadata: { + name: "Example JavaScript Dapp", + url: window.location.href, + }, + infuraAPIKey: process.env.INFURA_API_KEY, +}) + +const ethereum = MMSDK.getProvider() + +// Connect to MetaMask +const accounts = await MMSDK.connect() + +// Make requests +const result = await ethereum.request({ + method: "eth_accounts", + params: [] +}) +``` + +#### Pure JavaScript (CDN) + +```html + + + + +``` + +#### Node.js + +```javascript +import { MetaMaskSDK } from "@metamask/sdk" + +const MMSDK = new MetaMaskSDK({ + dappMetadata: { + name: "Node.js dapp", + }, + infuraAPIKey: process.env.INFURA_API_KEY, +}) + +// Connect and get accounts +const accounts = await MMSDK.connect() +console.log("Connected accounts:", accounts) + +// Access provider +const provider = MMSDK.getProvider() +``` + +### Configuration Options + +The SDK accepts several options when initializing: + +```javascript +const MMSDK = new MetaMaskSDK({ + // Required - your dapp's info + dappMetadata: { + name: "Your Dapp Name", + url: window.location.href, + }, + + // Optional - Infura API key for read-only RPC calls + infuraAPIKey: process.env.INFURA_API_KEY, + + // Optional - customize modal display + headless: false, +}) +``` + +### Common SDK Methods + +```javascript +// Connect and get accounts +const accounts = await MMSDK.connect() + +// Get provider for RPC requests +const provider = MMSDK.getProvider() + +// Make an RPC request +const result = await provider.request({ + method: "eth_accounts", + params: [] +}) + +// Connect and sign in one step +const signResult = await MMSDK.connectAndSign({ + msg: "Sign in to Dapp" +}) + +// Batch multiple RPC requests +const batchResults = await provider.request({ + method: "metamask_batch", + params: [ + { method: "eth_accounts" }, + { method: "eth_chainId" } + ] +}) +``` diff --git a/sdk/quick-start/react-native.md b/sdk/quick-start/react-native.md new file mode 100644 index 00000000000..33a8bea292e --- /dev/null +++ b/sdk/quick-start/react-native.md @@ -0,0 +1,204 @@ +--- +description: React Native +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# React Native + +This guide covers setting up MetaMask SDK in your React Native or Expo application. With MetaMask SDK, you can enable your users to easily connect to the MetaMask browser extension and MetaMask Mobile. + +### Prerequisites + +- MetaMask Mobile v5.8.1+ +- npm installed + +### Create Project + + + + +```bash +npx react-native@latest init MyProject +``` + + + + +```bash +npx create-expo-app devexpo --template +``` + + + + +### Install Dependencies + + + + +```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 +``` + + + + +### Configure Metro + +For Expo, first generate the config: +```bash +npx expo customize metro.config.js +``` + +Update your Metro configuration: + + + + +```javascript +const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config") + +const defaultConfig = getDefaultConfig(__dirname) + +const config = { + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, + resolver: { + extraNodeModules: { + ...require("node-libs-react-native"), + }, + }, +} + +module.exports = mergeConfig(defaultConfig, config) +``` + + + + +```javascript +const config = getDefaultConfig(__dirname) + +config.resolver.extraNodeModules = { + ...require("node-libs-expo"), +} + +config.transformer.getTransformOptions = async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, +}) + +module.exports = config +``` + + + + +### Add Required Imports + + + + +```javascript +// index.js or App.tsx +import "node-libs-react-native/globals" +import "react-native-url-polyfill/auto" +import "react-native-get-random-values" +``` + + + + +```javascript +// App.tsx +import "node-libs-expo/globals" +import "react-native-url-polyfill/auto" +import "react-native-get-random-values" +``` + + + + +### Build & Run + + + + +```bash +npx react-native run-android +npx react-native run-ios +``` + + + + +```bash +# Prebuild first +npx expo prebuild + +# Then run +npx expo run:android +npx expo run:ios +``` + + + + +### Using the SDK + +Here's how to integrate MetaMask SDK in your app: + +```javascript +import { useSDK } from "@metamask/sdk-react" + +function App() { + const { connect, disconnect, account, chainId, ethereum } = useSDK() + + // Connect to MetaMask + const connectWallet = async () => { + try { + await connect() + } catch (error) { + console.error("Failed to connect wallet:", error) + } + } + + // Handle state changes + useEffect(() => { + if (account && chainId) { + // Handle account and network changes + } + }, [account, chainId]) + + // Disconnect wallet + const disconnectWallet = async () => { + await disconnect() + } + + return ( + // Your app UI + ) +} +``` + +### Example Projects + +- [React Native Demo](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/reactNativeDemo) +- [Expo Demo](https://github.com/MetaMask/metamask-sdk/tree/main/packages/examples/expo-demo) \ No newline at end of file diff --git a/src/components/Card.tsx b/src/components/Card.tsx index 62775d60ccb..1426fa8bf61 100644 --- a/src/components/Card.tsx +++ b/src/components/Card.tsx @@ -6,18 +6,25 @@ import styles from "./card.module.css"; export type CardItem = { title: string; + subtitle?: string; link: string; description: JSX.Element; }; -export default function Card({ title, link, description }: CardItem) { +export default function Card({ title, subtitle, link, description }: CardItem) { return (
- {title} + + {title} + {subtitle && {subtitle}} + +
+
{description}
+
+ Get started
-
{description}
); diff --git a/src/components/CardSection.tsx b/src/components/CardSection.tsx index 9a851a27446..0883b53bdd7 100644 --- a/src/components/CardSection.tsx +++ b/src/components/CardSection.tsx @@ -1,36 +1,36 @@ import React from "react"; +import clsx from "clsx"; import Card, { type CardItem } from "@site/src/components/Card"; import styles from "./cardsection.module.css"; const CardList: CardItem[] = [ { - title: "📱 Integrate your dapp with the MetaMask wallet", + title: "Wallet", + subtitle: "Integrate with MetaMask Wallet", link: "/wallet", description: ( <> - Integrate your dapp with MetaMask using MetaMask SDK and the Wallet API. - You can interact with your users' EVM accounts from multiple dapp platforms. + Interact with your users' via the MetaMask Wallet API. ), }, { - title: "🛠️ Extend the functionality of MetaMask using Snaps", - link: "/snaps", + title: "SDK", + subtitle: "Build on chain apps", + link: "/sdk", description: ( <> - Extend the functionality of MetaMask using Snaps. You can create a Snap - to add support for custom networks, account types, APIs, and more. + Authenticate users, handle transactions, interact with contracts, and more. ), }, { - title: "📐 Build and scale your dapp using services", - link: "/services", + title: "Snaps", + subtitle: "Extend the functionality of MetaMask", + link: "/snaps", description: ( <> - Build and scale your dapp or Snap using services provided by MetaMask - and Infura. This includes APIs that optimize essential development - tasks. + Extend the functionality with custom networks, account types, APIs, and more. ), }, @@ -38,11 +38,13 @@ const CardList: CardItem[] = [ export default function CardSection(): JSX.Element { return ( -
-
- {CardList.map((props, idx) => ( - - ))} +
+
+
+ {CardList.map((props, idx) => ( + + ))} +
); diff --git a/src/components/card.module.css b/src/components/card.module.css index 5426ff45911..adf1091ae5c 100644 --- a/src/components/card.module.css +++ b/src/components/card.module.css @@ -21,3 +21,21 @@ display: flex; flex-direction: column; } + +.cardBody { + flex: 1; + padding-left: var(--ifm-card-horizontal-spacing); + padding-right: var(--ifm-card-horizontal-spacing); +} + +.ctaButton { + background-color: #1098fc; + border-radius: 0.3rem; + max-width: 12rem; + align-self: self-end; + margin: 1rem; +} + +.ctaButton:hover { + background-color: #43aefc; +} \ No newline at end of file diff --git a/src/components/cardsection.module.css b/src/components/cardsection.module.css index 2d7b80d06de..9404da13d4c 100644 --- a/src/components/cardsection.module.css +++ b/src/components/cardsection.module.css @@ -1,3 +1,7 @@ +.cardSection { + background-color: #2b3137; +} + .row { display: flex; flex-wrap: wrap; diff --git a/src/css/custom.css b/src/css/custom.css index 8a1e5dc898e..39ed57950ca 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -395,4 +395,4 @@ button:hover { .react-dropdown-select.select-lang .react-dropdown-select-dropdown-handle{ color: #fff; -} +} \ No newline at end of file diff --git a/src/pages/index.module.css b/src/pages/index.module.css index 616e317ee89..fe1ef428e6b 100644 --- a/src/pages/index.module.css +++ b/src/pages/index.module.css @@ -7,7 +7,10 @@ .introductionBlock { background-color: #2b3137; - padding: 6rem; + padding-top: 6rem; + padding-bottom: 3rem; + padding-left: 6rem; + padding-right: 6rem; text-align: center; width: 100%; } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 25899222a30..4203aece6f5 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -10,7 +10,7 @@ import styles from "./index.module.css"; function HomepageHeader() { const { siteConfig } = useDocusaurusContext(); return ( -
+
- Integrate with and extend upon the world's leading self-custodial - crypto wallet. + Build with the world's leading self-custodial crypto wallet.

- - Get started -
); diff --git a/vercel.json b/vercel.json index f68b497aa3b..18ca0a1f237 100644 --- a/vercel.json +++ b/vercel.json @@ -32,103 +32,99 @@ }, { "source": "/guide/metamask-extension-provider/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/quickstart/javascript/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/quickstart/react/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/quickstart/other-platforms/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/how-to/discover-multiple-wallets/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/how-to/detect-wallet/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/how-to/detect-wallet/multiple-wallets/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/how-to/access-provider/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/how-to/use-3rd-party-integrations/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/how-to/use-sdk/3rd-party-libraries/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/how-to/connect/", - "destination": "/wallet/connect/" + "destination": "/wallet/" }, { "source": "/wallet/how-to/connect/set-up-sdk/:path*/", - "destination": "/wallet/connect/metamask-sdk/:path*/" + "destination": "/sdk/" }, { "source": "/wallet/how-to/use-sdk/:path*/", - "destination": "/wallet/connect/metamask-sdk/:path*/" + "destination": "/sdk/" }, { "source": "/wallet/concepts/sdk/", - "destination": "/wallet/connect/metamask-sdk/" + "destination": "/sdk/" }, { "source": "/guide/mobile-getting-started/", - "destination": "/wallet/connect/metamask-sdk/" + "destination": "/sdk/" }, { "source": "/guide/site-compatibility-checklist/", - "destination": "/wallet/connect/metamask-sdk/" + "destination": "/sdk/" }, { "source": "/guide/mobile-best-practices/", - "destination": "/wallet/connect/metamask-sdk/" + "destination": "/sdk/" }, { "source": "/wallet/how-to/use-mobile/", - "destination": "/wallet/connect/metamask-sdk/" + "destination": "/sdk/" }, { "source": "/wallet/how-to/integrate-with-mobile/", - "destination": "/wallet/connect/metamask-sdk/" - }, - { - "source": "/sdk/", - "destination": "/wallet/connect/metamask-sdk/" + "destination": "/sdk/" }, { "source": "/wallet/how-to/connect/set-up-sdk/javascript/react-native/", - "destination": "/wallet/connect/metamask-sdk/mobile/react-native/" + "destination": "/sdk/quick-start/react-native/" }, { "source": "/wallet/how-to/use-sdk/javascript/react-native/", - "destination": "/wallet/connect/metamask-sdk/mobile/react-native/" + "destination": "/sdk/quick-start/react-native/" }, { "source": "/wallet/how-to/use-sdk/3rd-party-libraries/wagmi/", - "destination": "/wallet/connect/3rd-party-libraries/wagmi/" + "destination": "/sdk/quick-start/javascript-+-wagmi/" }, { "source": "/wallet/how-to/use-3rd-party-integrations/web3-onboard/", - "destination": "/wallet/connect/3rd-party-libraries/web3-onboard/" + "destination": "/sdk/" }, { "source": "/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard/", - "destination": "/wallet/connect/3rd-party-libraries/web3-onboard/" + "destination": "/sdk/" }, { "source": "/wallet/category/how-to/", @@ -168,7 +164,7 @@ }, { "source": "/wallet/how-to/use-sdk/javascript/connect-and-sign/", - "destination": "/wallet/how-to/sign-data/connect-and-sign/" + "destination": "/sdk/guides/advanced/connect-and-sign/" }, { "source": "/wallet/how-to/use-siwe/", @@ -180,15 +176,15 @@ }, { "source": "/wallet/how-to/use-3rd-party-integrations/js-infura-api/", - "destination": "/wallet/how-to/make-read-only-requests/" + "destination": "/sdk/" }, { "source": "/wallet/how-to/use-sdk/javascript/make-read-only-requests/", - "destination": "/wallet/how-to/make-read-only-requests/" + "destination": "/sdk/guides/advanced/batch-requests/" }, { "source": "/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests/", - "destination": "/wallet/how-to/batch-json-rpc-requests/" + "destination": "/sdk/guides/advanced/batch-requests/" }, { "source": "/guide/registering-your-token/", @@ -292,7 +288,7 @@ }, { "source": "/wallet/concepts/sdk/connections/", - "destination": "/wallet/concepts/sdk-connections/" + "destination": "/sdk/" }, { "source": "/wallet/concepts/sdk/android/", diff --git a/wallet-sidebar.js b/wallet-sidebar.js index 6dfce855f56..2fea02aba73 100644 --- a/wallet-sidebar.js +++ b/wallet-sidebar.js @@ -4,135 +4,13 @@ const sidebar = { walletSidebar: [ { - type: "doc", - label: "Introduction", - id: "index", - }, - { - type: "category", - label: "Connect to MetaMask", - collapsible: true, + type: 'category', + label: 'Introduction', + collapsible: false, collapsed: false, - link: { type: "doc", id: "connect/index" }, items: [ - { - type: "category", - label: "MetaMask SDK", - collapsible: true, - collapsed: true, - link: { type: "doc", id: "connect/metamask-sdk/index" }, - items: [ - { - type: "category", - label: "JavaScript", - collapsible: true, - collapsed: true, - link: { type: "doc", id: "connect/metamask-sdk/javascript/index" }, - items: [ - { - type: "category", - label: "React", - collapsible: true, - collapsed: true, - link: { type: "doc", id: "connect/metamask-sdk/javascript/react/index" }, - items: [ - { - type: "doc", - label: "React UI", - id: "connect/metamask-sdk/javascript/react/react-ui" - }, - ], - }, - { - type: "doc", - label: "Pure JavaScript", - id: "connect/metamask-sdk/javascript/pure-js" - }, - { - type: "doc", - label: "Other web frameworks", - id: "connect/metamask-sdk/javascript/other-web-frameworks" - }, - { - type: "doc", - label: "Node.js", - id: "connect/metamask-sdk/javascript/nodejs" - }, - { - type: "doc", - label: "Electron", - id: "connect/metamask-sdk/javascript/electron" - }, - ], - }, - { - type: "category", - label: "Mobile", - collapsible: true, - collapsed: true, - link: { type: "doc", id: "connect/metamask-sdk/mobile/index" }, - items: [ - { - type: "doc", - label: "iOS", - id: "connect/metamask-sdk/mobile/ios" - }, - { - type: "doc", - label: "Android", - id: "connect/metamask-sdk/mobile/android" - }, - { - type: "doc", - label: "React Native", - id: "connect/metamask-sdk/mobile/react-native" - }, - ], - }, - { - type: "category", - label: "Gaming", - collapsible: true, - collapsed: true, - link: { type: "doc", id: "connect/metamask-sdk/gaming/index" }, - items: [ - { - type: "doc", - label: "Unity", - id: "connect/metamask-sdk/gaming/unity" - } - ], - }, - ], - }, - { - type: "category", - label: "Third-party libraries", - collapsible: true, - collapsed: true, - link: { - type: "generated-index", - slug: "/connect/3rd-party-libraries", - description: "You can connect to MetaMask using third-party libraries that integrate MetaMask SDK." - }, - items: [ - { - type: "doc", - label: "Wagmi", - id: "connect/3rd-party-libraries/wagmi" - }, - { - type: "doc", - label: "Web3-Onboard", - id: "connect/3rd-party-libraries/web3-onboard" - }, - ], - }, - { - type: "doc", - label: "Wallet API", - id: "connect/wallet-api", - }, + 'introduction/welcome', + 'introduction/wallet-api', ], }, { @@ -173,11 +51,6 @@ const sidebar = { collapsed: true, link: { type: "doc", id: "how-to/sign-data/index" }, items: [ - { - type: "doc", - label: "Connect and sign", - id: "how-to/sign-data/connect-and-sign" - }, { type: "doc", label: "Sign in with Ethereum", @@ -190,16 +63,6 @@ const sidebar = { label: "Send transactions", id: "how-to/send-transactions" }, - { - type: "doc", - label: "Make read-only requests", - id: "how-to/make-read-only-requests" - }, - { - type: "doc", - label: "Batch JSON-RPC requests", - id: "how-to/batch-json-rpc-requests" - }, { type: "category", label: "Display in MetaMask", @@ -221,11 +84,6 @@ const sidebar = { type: "doc", label: "Display a dapp icon", id: "how-to/display/icon" - }, - { - type: "doc", - label: "Display custom modals", - id: "how-to/display/custom-modals" } ] }, @@ -290,59 +148,6 @@ const sidebar = { } ] }, - { - type: "category", - label: "Use the Unity SDK", - collapsible: true, - collapsed: true, - link: { type: "doc", id: "how-to/use-unity-sdk/index" }, - items: [ - { - type: "doc", - label: "Connect and sign", - id: "how-to/use-unity-sdk/connect-and-sign" - }, - { - type: "doc", - label: "Set up Infura", - id: "how-to/use-unity-sdk/infura" - }, - { - type: "category", - label: "Interact with smart contracts", - collapsible: true, - collapsed: true, - link: { type: "doc", id: "how-to/use-unity-sdk/smart-contracts/index" }, - items: [ - { - type: "doc", - label: "Contract interface", - id: "how-to/use-unity-sdk/smart-contracts/contract-interface" - }, - { - type: "doc", - label: "Contract factory", - id: "how-to/use-unity-sdk/smart-contracts/contract-factory" - }, - { - type: "doc", - label: "Contract proxy class", - id: "how-to/use-unity-sdk/smart-contracts/contract-proxy-class" - }, - { - type: "doc", - label: "Contract provider", - id: "how-to/use-unity-sdk/smart-contracts/contract-provider" - } - ] - }, - { - type: "doc", - label: "Enable human-readable addresses", - id: "how-to/use-unity-sdk/dweb" - } - ] - }, { type: "doc", label: "Onboard users", @@ -367,26 +172,11 @@ const sidebar = { collapsed: true, link: { type: "generated-index", slug: "/concepts" }, items: [ - { - type: "doc", - label: "Architecture", - id: "concepts/architecture" - }, { type: "doc", label: "About the Wallet API", id: "concepts/wallet-api" }, - { - type: "doc", - label: "SDK connections", - id: "concepts/sdk-connections" - }, - { - type: "doc", - label: "Android SDK architecture", - id: "concepts/android-sdk" - }, { type: "doc", label: "Convenience libraries", @@ -431,11 +221,6 @@ const sidebar = { label: "Create a simple dapp", id: "tutorials/javascript-dapp-simple", }, - { - type: "doc", - label: "Create a dapp with the SDK and Wagmi", - id: "tutorials/react-dapp-sdk-wagmi", - }, ], }, { @@ -445,16 +230,6 @@ const sidebar = { collapsed: false, link: { type: "generated-index", slug: "/reference" }, items: [ - { - type: "doc", - label: "JavaScript SDK options", - id: "reference/sdk-js-options", - }, - { - type: "doc", - label: "Unity SDK API", - id: "reference/sdk-unity-api", - }, { type: "category", label: "Non-EVM APIs", diff --git a/wallet/index.md b/wallet/index.md deleted file mode 100644 index 4153406a008..00000000000 --- a/wallet/index.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -description: Integrate your dapp with the MetaMask wallet. ---- - -# Integrate your dapp with the MetaMask wallet - -Integrate your dapp with MetaMask using **MetaMask SDK** and the **Wallet API**. -Use MetaMask SDK to create a seamless connection between your dapp and MetaMask across desktop and -mobile platforms. -Use the Wallet API to interact with users' EVM accounts in MetaMask. - -Get started by [connecting to MetaMask](connect/index.md). - -## Why use MetaMask SDK? - -**MetaMask SDK** enables a reliable, secure, and seamless connection between your dapp and the -MetaMask browser extension or MetaMask Mobile, providing cross-platform compatibility with a -consistent user experience. -Key benefits include: - -- **Multi-platform support** - Connect from web, desktop, mobile, and gaming platforms. -- **Seamless connections** - Minimize reconnections and improve user experience, especially on mobile. -- **Mobile-first optimization** - Enable faster wallet interactions with instant deeplinks and advanced features. -- **Enhanced functionality** - Use [RPC request batching](how-to/batch-json-rpc-requests.md), - [EIP-6963](/wallet/concepts/wallet-interoperability.md) for wallet discovery, and wallet security enhancements. -- **Third-party library integration** - Use libraries like [Wagmi](connect/3rd-party-libraries/wagmi.md) - or [Web3-Onboard](connect/3rd-party-libraries/web3-onboard.md) that integrate SDK support. - -The **Wallet API** allows you to interact with users' EVM accounts using standardized JSON-RPC calls. -While you can connect to the MetaMask extension directly using just the Wallet API, we recommend -using the SDK or third-party libraries in conjunction with the Wallet API, to take advantage of the -SDK's benefits. - -## Where do I start? - -See [**Connect to MetaMask**](connect/index.md) to learn about the different connection options, -and get started quickly. - -## Questions? - -For more support, connect with the MetaMask team and community on [Consensys Discord](https://discord.gg/consensys). - -:::note MetaMask user support -For MetaMask user support, visit the [MetaMask Help Center](https://support.metamask.io/). -::: diff --git a/wallet/connect/wallet-api.md b/wallet/introduction/wallet-api.md similarity index 99% rename from wallet/connect/wallet-api.md rename to wallet/introduction/wallet-api.md index 785d6afda86..946e3a3d8f1 100644 --- a/wallet/connect/wallet-api.md +++ b/wallet/introduction/wallet-api.md @@ -3,7 +3,7 @@ description: Connect to MetaMask using the Wallet API and EIP-6963. toc_max_heading_level: 4 --- -# Connect to MetaMask using the Wallet API +# Wallet API You can connect your dapp to users' MetaMask wallets by detecting MetaMask in their browsers and connecting to their accounts. diff --git a/wallet/introduction/welcome.md b/wallet/introduction/welcome.md new file mode 100644 index 00000000000..8ea498825a1 --- /dev/null +++ b/wallet/introduction/welcome.md @@ -0,0 +1,32 @@ +--- +slug: / +description: Welcome to the MetaMask Wallet API documentation +--- + +# Welcome + +Welcome to the **MetaMask Wallet API** documentation! + +:::tip Building a cross-platform or mobile app? +For cross-platform development, mobile integration, or advanced features like QR codes and deep linking, check out the [**MetaMask SDK** docs](https://docs.metamask.io/sdk/). +::: + +## What is the Wallet API? + +The Wallet API is MetaMask's core interface for web applications to interact with the MetaMask browser extension. It enables you to: + +- Connect web dApps to MetaMask browser extension +- Interact with users' Ethereum accounts +- Send transactions and sign messages +- Listen to account and network changes +- Use the provider methods +- Use the JSON-RPC methods + +The Wallet API uses standardized JSON-RPC calls to interact with users' EVM accounts and implements standard interfaces like [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) for Ethereum provider methods and [EIP-6963](https://eips.ethereum.org/EIPS/eip-6963) for wallet detection. + +## Wallet API vs SDK + +The **Wallet API** is designed for web applications that connect to the MetaMask browser extension. If you're building a desktop web-only dApp, the Wallet API provides everything you need. + +The **MetaMask SDK** builds on top of the Wallet API, adding cross-platform support and features like mobile deep linking and QR code connections. SDK is recommended if you want to build a cross-platform on chain apps. +