diff --git a/wallet-sidebar.js b/wallet-sidebar.js index d4cf51e5fb..4aea5da931 100644 --- a/wallet-sidebar.js +++ b/wallet-sidebar.js @@ -36,6 +36,12 @@ const sidebar = { type: "doc", id: "reference/sdk-unity-api", }, + { + type: "category", + label: "Non-EVM APIs", + link: { type: "generated-index", slug: "/reference/non-evm-apis" }, + items: [{ type: "autogenerated", dirName: "reference/non-evm-apis" }], + }, { type: "doc", id: "reference/provider-api", diff --git a/wallet/how-to/connect/access-accounts.md b/wallet/how-to/connect/access-accounts.md index e071a9ed51..f527c79e3f 100644 --- a/wallet/how-to/connect/access-accounts.md +++ b/wallet/how-to/connect/access-accounts.md @@ -24,6 +24,10 @@ When accessing a user's accounts: - **Always** disable the connect button while the connection request is pending. - **Never** initiate a connection request on page load. +:::note +You can also access users' accounts on some [non-EVM networks](/wallet/how-to/use-non-evm-networks). +::: + ## Create a connect button :::caution Important diff --git a/wallet/how-to/manage-networks/add-network.md b/wallet/how-to/manage-networks/add-network.md index 06daa7b734..88521ba4ec 100644 --- a/wallet/how-to/manage-networks/add-network.md +++ b/wallet/how-to/manage-networks/add-network.md @@ -30,10 +30,10 @@ The confirmations look like the following: -:::note - -To add a local development network such as [Hardhat](https://hardhat.org) to MetaMask, see [Run a development network](../run-devnet.md). - +:::info Development and non-EVM networks +- To add a local development network such as [Hardhat](https://hardhat.org) to MetaMask, see [Run a development network](../run-devnet.md). +- To add a non-EVM network such as [Starknet](../use-non-evm-networks/starknet/index.md) to MetaMask, + see [Use non-EVM networks](/wallet/how-to/use-non-evm-networks). ::: ## Example diff --git a/wallet/how-to/run-devnet.md b/wallet/how-to/run-devnet.md index 23ff930166..436a8c5026 100644 --- a/wallet/how-to/run-devnet.md +++ b/wallet/how-to/run-devnet.md @@ -1,6 +1,6 @@ --- description: Configure and connect to a Ganache development network. -sidebar_position: 9 +sidebar_position: 10 --- # Run a development network diff --git a/wallet/how-to/use-non-evm-networks/index.md b/wallet/how-to/use-non-evm-networks/index.md new file mode 100644 index 0000000000..e63ff72ad6 --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/index.md @@ -0,0 +1,32 @@ +--- +description: Interact with users' accounts on non-EVM networks. +sidebar_position: 9 +--- + +import CardList from "@site/src/components/CardList" + +# Use non-EVM networks + +You can interact with users' accounts on non-EVM networks by connecting to existing +[MetaMask Snaps](https://metamask.io/snaps/). + +Non-EVM networks are blockchain networks that are not compatible with the Ethereum Virtual Machine (EVM). +Non-EVM dapps and MetaMask can't directly interact with each other. +By connecting to dedicated non-EVM Snaps, you can extend the functionality of MetaMask and integrate non-EVM networks into your existing MetaMask workflow. + +MetaMask provides Snaps for the following networks: + + + +:::info +See the [full list of available non-EVM Snaps](https://snaps.metamask.io/interoperability). +::: diff --git a/wallet/how-to/use-non-evm-networks/starknet/about-get-starknet.md b/wallet/how-to/use-non-evm-networks/starknet/about-get-starknet.md new file mode 100644 index 0000000000..bb4ebfc25c --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/about-get-starknet.md @@ -0,0 +1,87 @@ +--- +description: Learn about how `get-starknet` interacts with MetaMask. +sidebar_position: 8 +--- + +# About `get-starknet` + +[`get-starknet`](https://github.com/starknet-io/get-starknet) is a library that simplifies Starknet +network interactions. +It works with the [Starknet Snap](https://snaps.metamask.io/snap/npm/consensys/starknet-snap/) to +enable dapps to interact with users' Starknet accounts in MetaMask. + +When you integrate `get-starknet` into your dapp, it creates a [Starknet +Windows Object (SWO)](https://github.com/starknet-io/get-starknet/blob/get-starknet-core%403.3.0/packages/core/src/StarknetWindowObject.ts), which acts as +the connection between the dapp and MetaMask, and manages Starknet interactions. +This allows users to send Starknet transactions, sign Starknet messages, and manage Starknet +accounts within MetaMask, and this functionality can be extended to multiple wallets in the Starknet +ecosystem. + +## How `get-starknet` and MetaMask interact + +A dapp with `get-starknet` installed interacts with MetaMask as follows: + +1. The dapp uses `get-starknet` to request the user connect to MetaMask. + MetaMask automatically requests the user to add the Starknet Snap, if it's not already present. + +1. After the dapp is connected to MetaMask and the Starknet Snap, `get-starknet` receives a Starknet + Windows Object (SWO), which represents the MetaMask wallet with Starknet functionality. + +1. You can retrieve an [Account Object](https://starknetjs.com/docs/API/#account) from the Starknet Windows Object (SWO) when you access `swo.account`. + This Account Object enables you to manage Starknet interactions. + This instance manages the Starknet account within MetaMask. + +```mermaid +sequenceDiagram + participant user as End User + participant dapp as Dapp + participant get as get-starknet + participant mm as MetaMask + participant Snap as Starknet Snap + participant network as Starknet network + + dapp->>get: Initialize connection + get->>mm: Request connection + mm->>Snap: Activate + Snap-->>mm: Activated + get->>Snap: Request Starknet account address + Snap-->>mm: Recover account and return Starknet account address + mm-->>get: Return Starknet account address + get-->>dapp: Connection established with SWO return + + dapp->>get: Read blockchain data + get->>network: Query data + network-->>get: Return data + get-->>dapp: Processed data + + dapp->>get: Write transaction + get->>mm: Request write transaction + mm->>Snap: write transaction + Snap-->>mm: Request confirmation to write transaction + mm-->>user: Request confirmation + user-->>mm: Confirm transaction + mm-->>Snap: Confirm transaction + + alt If the Account has deployed + Snap-->>network: deploying account transaction + end + Snap-->>network: Submit transaction + network-->>Snap: Transaction result + Snap-->>mm: Return Transaction result + mm-->>get: Return Transaction result + get-->>dapp: Return Transaction result +``` + +The `get-starknet` library offers several features that improve how dapps interact with the Starknet +network through MetaMask: + +- The `AccountInterface` uses a specified provider to access data from the Starknet network. +- For transactions, `get-starknet` prepares the data and sends it to MetaMask for signing through + the Starknet Snap. +- `get-starknet` enables the dapp to create contract instances connected to the `AccountInterface`, + allowing smart contract functions to be invoked, with MetaMask handling the signatures. +- `get-starknet` sets up listeners for account and network changes in MetaMask, so the dapp can + subscribe and update its state accordingly. +- `get-starknet` can request network changes through MetaMask, allowing users to switch between + Starknet networks, such as Mainnet and Sepolia testnet. +- `get-starknet` can also request MetaMask to display specific tokens, improving the user experience. diff --git a/wallet/how-to/use-non-evm-networks/starknet/connect-to-starknet.md b/wallet/how-to/use-non-evm-networks/starknet/connect-to-starknet.md new file mode 100644 index 0000000000..cac33a6818 --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/connect-to-starknet.md @@ -0,0 +1,402 @@ +--- +description: Connect your dapp to Starknet in MetaMask. +sidebar_position: 1 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Connect to Starknet + +Connect your dapp to Starknet in MetaMask by using the +[`get-starknet`](#connect-using-get-starknet) library or the +[`wallet_invokeSnap`](#connect-using-wallet_invokesnap) JSON-RPC method. + +:::warning Important + +We recommend using the `get-starknet` library for most use cases due to its ease of configuration +and multi-wallet support. +See [a comparison of the connection options](index.md#connection-options). + +::: + +:::tip +If you're new to Starknet, you can also follow the +[Create a simple Starknet dapp tutorial](create-a-simple-starknet-dapp.md). +::: + +## Prerequisites + +- [MetaMask installed](https://metamask.io/download/) +- A text editor (for example, [VS Code](https://code.visualstudio.com/)) +- [Node](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) version 20.11 or later +- [Yarn](https://yarnpkg.com/) +- (Optional) A JavaScript or TypeScript React project set up + +## Connect using `get-starknet` + +### 1. Set up the project + +If you don't have an existing React project set up, you can create a new +[React project](https://create-react-app.dev/) project with TypeScript and set up the necessary dependencies for working with Starknet. + +Create a new directory called `get-starknet-dapp` with a basic React app using TypeScript: + + + + +```bash +yarn create react-app get-starknet-dapp +``` + + + + +```bash +npm create react-app get-starknet-dapp +``` + + + + +Change into the project directory: + +```bash +cd get-starknet-dapp +``` + +### 2. Add `get-starknet` and `starknet.js` + +Add [`get-starknet`](https://github.com/starknet-io/get-starknet) version `3.3.0` and `starknet.js` +version `6.11.0` to your project's dependencies: + + + + + ```bash + yarn add get-starknet@3.3.0 starknet@6.11.0 + ``` + + + + + + ```bash + npm install get-starknet@3.3.0 starknet@6.11.0 + ``` + + + + +### 3. Connect to the Snap + +Create a `src/components` directory, and add a new file named `WalletConnectButton.js` to the directory. +Add the following code to the file, which handles the connection to the Snap and displays a button +for users to initiate the wallet connection: + +```javascript title="WalletConnectButton.js" +import React, { useState } from "react"; +import { connect, disconnect } from "get-starknet"; +import { encode } from "starknet"; +function WalletConnectButton() { + const [walletAddress, setWalletAddress] = useState(""); + const [walletName, setWalletName] = useState(""); + const [wallet, setWallet] = useState(""); + const handleDisconnect = async () => { + await disconnect({clearLastWallet: true}); + setWallet(""); + setWalletAddress(""); + setWalletName("") + } + const handleConnect = async () => { + try{ + const getWallet = await connect({ modalMode: "alwaysAsk", modalTheme: "light" }); + await getWallet?.enable({ starknetVersion: "v5" }); + setWallet(getWallet); + const addr = encode.addHexPrefix(encode.removeHexPrefix(getWallet?.selectedAddress ?? "0x").padStart(64, "0")); + setWalletAddress(addr); + setWalletName(getWallet?.name || "") + } + catch(e){ + // Handle user rejection to install MetaMask / the Starknet Snap. + console.log(e) + } + }; + return ( +
+ {!walletAddress && ( + + )} + {walletAddress && ( +
+ +
+

Wallet Name: {walletName}

+

Wallet Address: {walletAddress}

+
+
+ )} +
+ ); +} +export default WalletConnectButton; +``` + +:::note + +This code automatically requests the user to add the +[Starknet Snap](https://snaps.metamask.io/snap/npm/consensys/starknet-snap/) to MetaMask, if it's +not already present. +Handle the error if the user rejects the connection request in the `try` / `catch` block of the +`handleConnect` function. + +::: + +Add a new file named `App.js` to the `src` directory, and add the following code to the file to use +the `WalletConnectButton` component: + +```js title="App.js" +import WalletConnectButton from "./components/WalletConnectButton.js" + +function App() { + return ( +
+
+ +
+
+ ); +} + +export default App; +``` + +### 4. Start the dapp + +Start the dapp and navigate to it in your browser. +A **Connect Wallet** button displays, which allows users to connect to MetaMask and interact with Starknet. + + + + + ```bash + yarn start + ``` + + + + + + ```bash + npm start + ``` + + + + +The `get-starknet` library automatically handles detecting and connecting to MetaMask, and adding the Starknet Snap. + +## Connect using `wallet_invokeSnap` + +Alternatively, you can manage the Snap invocation manually. +Use the [`wallet_invokeSnap`](/snaps/reference/wallet-api-for-snaps/#wallet_invokesnap) JSON-RPC +method to directly interact with the Starknet Snap. + +### 1. Connect to the Snap + +Create a `src/utils` directory, and add a new file named `snapHelper.js` to the directory. +In `snapHelper.js`, add a `connect` function and a `callSnap` helper function as follows. +This file handles the interactions with the Starknet Snap: + +```javascript title="snapHelper.js" +const snapId = "npm:starknet-snap"; + +export async function connect() { + await ethereum.request({ + method: "wallet_requestSnaps", + params: { + [snapId]: {}, + }, + }); +} + +export async function callSnap(method, params) { + try { + const response = await ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId, + request: { + method, + params, + }, + }, + }); + console.log(`${method} response:`, response); + return response; + } catch (err) { + console.error(`${method} error:`, err); + alert(`${method} error: ${err.message || err}`); + throw err; + } +} +``` + +:::note + +To connect to Starknet, the dapp user must add the +[Starknet Snap](https://snaps.metamask.io/snap/npm/consensys/starknet-snap/) to MetaMask. + +::: + +### 2. Call a specific Snap method + +Use the `callSnap` function to call a specific Snap method. +The following example calls `starkNet_createAccount`: + +```javascript +const deploy = false; // Set to true to deploy the actual account. +const addressIndex = 0; // Specify which address to derive. +const chainId = "0x534e5f5345504f4c4941"; // Chain ID of the network to use. + +const accountInfo = await callSnap("starkNet_createAccount", { addressIndex, deploy, chainId }); +``` + +### Examples + +#### HTML and Vanilla JS + +The following is a full example of a simple HTML and Vanilla JavaScript dapp that connects to the +Starknet Snap using `wallet_invokeSnap`. +It displays a button that, when selected: + +- Connects to Starknet in MetaMask. +- Creates a Starknet account. +- Displays the account address. + +```html + + + + + Connect Starknet Snap + + + +

+ + + +``` + +#### React + +The following is a full example of a simple React component that connects to the Starknet Snap using +`wallet_invokeSnap`. + +```javascript +import React, { useState } from "react"; +const ConnectWallet = () => { + const [accountInfo, setAccountInfo] = useState(''); + const connect = async (snapId) => { + try { + await window.ethereum.request({ + method: "wallet_requestSnaps", + params: { + [snapId]: {}, + }, + }); + } catch (err) { + console.error("Snap connection error:", err); + alert(`Error connecting to Snap: ${err.message || err}`); + } + }; + const callSnap = async (snapId, method, params) => { + try { + const response = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId, + request: { + method, + params, + }, + }, + }); + return response; + } catch (err) { + console.error(`${method} problem happened:`, err); + alert(`${method} problem happened: ${err.message || err}`); + } + }; + const handleConnectClick = async () => { + try { + const snapId = "npm:@consensys/starknet-snap"; // Snap ID + await connect(snapId); + const deploy = false; // Whether to deploy the actual account. + const addressIndex = 0; // The address to derive. + const chainId = "0x534e5f5345504f4c4941"; // Chain ID of the network to use. + const account = await callSnap(snapId, "starkNet_createAccount", { addressIndex, deploy, chainId }); + setAccountInfo(`Connected Starknet Account: ${account.address}`); + } catch (error) { + console.error("Error connecting to Starknet Snap:", error); + } + }; + return ( +
+ +

{accountInfo}

+
+ ); +}; +export default ConnectWallet; +``` + +:::note +See how to [troubleshoot](troubleshoot.md) connection issues when configuring your dapp using `wallet_invokeSnap`. +::: diff --git a/wallet/how-to/use-non-evm-networks/starknet/create-a-simple-starknet-dapp.md b/wallet/how-to/use-non-evm-networks/starknet/create-a-simple-starknet-dapp.md new file mode 100644 index 0000000000..0035f574af --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/create-a-simple-starknet-dapp.md @@ -0,0 +1,369 @@ +--- +description: Create a simple dapp using `get-starknet` and React TypeScript. +sidebar_position: 6 +--- + +# Create a simple Starknet dapp + +In this tutorial, you'll learn how to set up a React TypeScript dapp that uses the [`get-starknet`](https://github.com/starknet-io/get-starknet) library to connect to MetaMask and display the user's wallet address. +You'll also display the balance of an ERC-20 token and perform a token transfer. + +## Prerequisites + +- [MetaMask installed](https://metamask.io/download/) +- A text editor (for example, [VS Code](https://code.visualstudio.com/)) +- [Node](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) version 20.11 or later +- [Yarn](https://yarnpkg.com/) + +## 1. Set up the project + +Create a new React project with TypeScript and set up the necessary dependencies for working with Starknet. + +Create a new directory called `get-starknet-tutorial` with a basic React app using TypeScript: + +```bash +yarn create react-app get-starknet-tutorial --template typescript +``` + +Change into the project directory: + +```bash +cd get-starknet-tutorial +``` + +## 2. Add `get-starknet` and `starknet.js` + +Add [`get-starknet`](https://github.com/starknet-io/get-starknet) version `3.3.0` and `starknet.js` +version `6.11.0` to your project's dependencies: + +```bash +yarn add get-starknet@3.3.0 starknet@6.11.0 +``` + +
+ Did you get an error? +
+ +See how to [troubleshoot](troubleshoot.md) connection issues when configuring your dapp. + +
+
+ +Your file structure should look similar to the following: + +```text +get-starknet-dapp/ +├── public/ +│ └── index.html +└── src/ + ├── components/ + │ ├── WalletConnect.tsx + ├── App.tsx + ├── index.tsx + └── App.css +``` + +## 2. Configure the wallet connection + +Use the `connect` function to link your dapp with a user’s MetaMask wallet. + +### 2.1. Connect to MetaMask + +The `connect` function from `get-starknet` is the primary way to connect your dapp to a user's MetaMask wallet. +It opens a connection to MetaMask and returns an object containing important details about the wallet, such as the following: + +- `name`: The name of the wallet. +- `icon`: The wallet's icon, which displays the wallet's logo. +- `account`: The account object from `starknet.js`, which contains the wallet's address and provides access to account-specific operations. + +To import the necessary functions and connect to a wallet, add the following code to `src/App.tsx`: + +```typescript title="App.tsx" +import { connect, type ConnectOptions } from "get-starknet"; + +async function handleConnect(options?: ConnectOptions) { + const res = await connect(options); + // Access wallet details such as name, address, and icon + console.log(res?.name, res?.account?.address, res?.icon); +} +``` + +### 2.2. Configure connection options + +`connect` accepts an optional `ConnectOptions` object. +This object can control the connection process, including: + +- `modalMode`: Determines how the connection modal behaves. The options are: + - `"alwaysAsk"`: Prompts the user every time a connection is initiated. + - `"neverAsk"`: Attempts to connect without showing the modal. +- `modalTheme`: Sets the visual theme of the connection modal. The options are `"dark"` and `"light"`. + +You can configure these options as follows: + +```typescript +handleConnect({ modalMode: "alwaysAsk", modalTheme: "dark" }); +``` + +### 2.3. Create an `AccountInterface` + +After connecting to MetaMask, create a new `AccountInterface` instance using the `starknet.js` library. +This allows interaction with the Starknet network using the connected wallet. + +```typescript title="App.tsx" +import { AccountInterface } from "starknet"; + +async function handleConnect(options?: ConnectOptions) { + const res = await connect(options); + const myFrontendProviderUrl = "https://free-rpc.nethermind.io/sepolia-juno/v0_7"; + const newAccountInterface = new AccountInterface({ nodeUrl: myFrontendProviderUrl }, res); +} +``` + +### 2.4. Display wallet information + +You can display the wallet's name, address, and icon in your dapp. +This provides visual feedback to the user, confirming which wallet they are using. + +The following code is an example of how to update the interface with the connected wallet's details: + +```typescript title="App.tsx" +import { useState } from "react"; + +function App() { + const [walletName, setWalletName] = useState(""); + const [walletAddress, setWalletAddress] = useState(""); + const [walletIcon, setWalletIcon] = useState(""); + + async function handleConnect(options?: ConnectOptions) { + const res = await connect(options); + setWalletName(res?.name || ""); + setWalletAddress(res?.account?.address || ""); + setWalletIcon(res?.icon || ""); + } + + return ( +
+

Selected Wallet: {walletName}

+

Address: {walletAddress}

+ Wallet icon +
+ ); +} +``` + +### 2.5. Full example + +The following is a full example of configuring the wallet connection: + +```typescript title="App.tsx" +import "./App.css" +import { + type ConnectOptions, + type DisconnectOptions, + connect, + disconnect, +} from "get-starknet" +import { AccountInterface } from "starknet"; +import { useState } from "react" + +function App() { + const [walletName, setWalletName] = useState("") + const [walletAddress, setWalletAddress] = useState("") + const [walletIcon, setWalletIcon] = useState("") + const [AccountInterface, setAccountInterface] = useState(null) + + async function handleConnect(options?: ConnectOptions) { + const res = await connect(options) + setWalletName(res?.name || "") + setWalletAddress(res?.account?.address || "") + setWalletIcon(res?.icon || "") + if (res) { + const myFrontendProviderUrl = "https://free-rpc.nethermind.io/sepolia-juno/v0_7"; + const newAccountInterface = new AccountInterface({ nodeUrl: myFrontendProviderUrl }, res) + setAccountInterface(newAccountInterface) + } + } + + async function handleDisconnect(options?: DisconnectOptions) { + await disconnect(options) + setWalletName("") + setWalletAddress("") + setAccountInterface(null) + } + + return ( +
+

get-starknet

+
+ + + + + + + +
+ {walletName && ( +
+

+ Selected Wallet:
{walletName}
+ Wallet icon +

+
    +
  • Wallet address:
    {walletAddress}
  • +
+
+ )} +
+ ) +}; + +export default App +``` + +## 3. Display the balance of and transfer an ERC-20 token + +Now that you have set up the basic interaction, you can display the balance of a specific ERC-20 token, such as STRK, and perform a transfer using the `AccountInterface` instance. + +### 3.1. Set up the contract + +To interact with an ERC-20 contract, create a contract instance from the `starknet.js` library using the `AccountInterface` instance. +The following example assumes the ABI (application binary interface) is loaded from a JSON file: + +```typescript +import { Contract } from "starknet"; +import erc20Abi from "./erc20Abi.json"; + +const tokenAddress = "0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7"; + +const erc20 = new Contract(erc20Abi, tokenAddress, AccountInterface); +``` + +:::note ABI and contract address +You can find the ABI of the ERC-20 contract on [Voyager](https://voyager.online/). + +The contract address for STRK (an ERC-20 token) on Sepolia testnet is `0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7`. +::: + +### 3.2. Fetch the token balance + +Call the `balanceOf` method to fetch the balance of the connected account: + +```typescript +const balance = await erc20.balanceOf(walletAddress); +const formattedBalance = balance / Math.pow(10, 18); +``` + +### 3.3. Transfer tokens + +To transfer tokens, fill out the `transfer` method call and execute the transaction using the `AccountInterface`. +For example: + +```typescript +import { Call } from "starknet"; + +// Define the transfer parameters. +const recipientAddress = "0x78662e7352d062084b0010068b99288486c2d8b914f6e2a55ce945f8792c8b1"; +const amountToTransfer = 1n * 10n ** 18n; // 1 token (assuming 18 decimals). + +const transferCall: Call = erc20.populate("transfer", { + recipient: recipientAddress, + amount: amountToTransfer, +}); + +// Execute the transfer. +const { transaction_hash: transferTxHash } = await AccountInterface.execute(transferCall); + +// Wait for the transaction to be accepted on Starknet. +await AccountInterface.waitForTransaction(transferTxHash); +``` + +### 3.4. Full example + +The following a full example of displaying the balance of an ERC-20 token and performing a transfer: + +```typescript +import { useEffect, useState } from "react"; +import { Contract } from "starknet"; +import erc20Abi from "./erc20Abi.json"; + +function TokenBalanceAndTransfer({ AccountInterface, tokenAddress }) { + const [balance, setBalance] = useState(null); + + useEffect(() => { + if (AccountInterface) { + const erc20 = new Contract(erc20Abi, tokenAddress, AccountInterface); + // Fetch balance + erc20.balanceOf(AccountInterface.address) + .then((result) => { + const formattedBalance = result / Math.pow(10, 18); // Adjust for decimals + setBalance(formattedBalance); + }) + .catch(console.error); + } + }, [AccountInterface, tokenAddress]); + + async function handleTransfer() { + if (AccountInterface) { + const erc20 = new Contract(erc20Abi, tokenAddress, AccountInterface); + const recipientAddress = "0x78662e7352d062084b0010068b99288486c2d8b914f6e2a55ce945f8792c8b1"; + const amountToTransfer = 1n * 10n ** 18n; // 1 token + + // Fill out and execute transfer + const transferCall: Call = erc20.populate("transfer", { + recipient: recipientAddress, + amount: amountToTransfer, + }); + const { transaction_hash: transferTxHash } = await AccountInterface.execute(transferCall); + + // Wait for the transaction to be accepted + await AccountInterface.provider.waitForTransaction(transferTxHash); + + // Refresh balance + const newBalance = await erc20.balanceOf(AccountInterface.address); + setBalance(newBalance / Math.pow(10, 18)); // Adjust for decimals + } + } + + return ( +
+

Token Balance: {balance !== null ? `${balance} STRK` : "Loading..."}

+ +
+ ); +} +``` + +## Next steps + +You've set up a simple React dapp that connects to MetaMask, displays an ERC-20 token balance, and performs token transfers. Creating a contract instance using `AccountInterface` allows you to interact with smart contracts, retrieve token balances, and execute transactions, enabling more advanced functionality in your dapp. + +You can follow these next steps: + +- [Manage Starknet accounts](manage-starknet-accounts.md). +- [Manage Starknet networks](manage-starknet-networks.md). +- Explore the [Starknet Snap API reference](../../../reference/non-evm-apis/starknet-snap-api.md). diff --git a/wallet/how-to/use-non-evm-networks/starknet/index.md b/wallet/how-to/use-non-evm-networks/starknet/index.md new file mode 100644 index 0000000000..547ad39ca4 --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/index.md @@ -0,0 +1,74 @@ +--- +description: Interact with users' Starknet accounts in MetaMask. +sidebar_position: 1 +--- + +# Use Starknet + +[Starknet](https://www.starknet.io/) is a non-EVM Layer 2 network. +You can interact with users' Starknet accounts in MetaMask by connecting to the +[Starknet Snap](https://snaps.metamask.io/snap/npm/consensys/starknet-snap/). + +You can use the [`get-starknet`](https://github.com/starknet-io/get-starknet) library or the +[`wallet_invokeSnap`](/snaps/reference/wallet-api-for-snaps/#wallet_invokesnap) JSON-RPC method from +your dapp to connect to the Starknet Snap. +See [Connect to Starknet](connect-to-starknet.md) to get started. + +## Connection options + +The [`get-starknet`](about-get-starknet) library: + +- Provides a high-level API that abstracts complex operations. +- Supports [a subset of the Starknet Snap API methods](#supported-methods). +- Standardizes error handling. +- Supports connecting to multiple Starknet wallets, not limited to MetaMask. +- Manages wallet connections and Starknet interactions. +- Provides results in more readable code. + +The [`wallet_invokeSnap`](/snaps/reference/wallet-api-for-snaps/#wallet_invokesnap) method: + +- Requires precise method names and parameter structures. +- Supports [all Starknet Snap API methods](#supported-methods). +- Handles both MetaMask-specific and Starknet-specific errors. +- Is designed for operating within the MetaMask framework. +- Manages lower-level Starknet interactions directly. +- Provides results in more detailed, lower-level code. + +:::warning Important + +We recommend using the `get-starknet` library for most use cases due to its ease of configuration +and multi-wallet support. +Learn more [about how `get-starknet` interacts with MetaMask](about-get-starknet.md). + +::: + +## Interaction with Starknet Snap + +After it is connected to the Starknet Snap, your dapp can interact with the Starknet network through two main integration options: `get-starknet` and `wallet_invokeSnap`. +Both options provide access to similar functionalities, but offer different ways of interacting with users' Starknet accounts. + +- `wallet_invokeSnap: Manages direct interactions between the dApp and the Starknet Snap. It facilitates network communication for account creation, transaction signing, fee estimation, and other Starknet-related actions. + +- `get-starknet`: Provides the same functionalities as `wallet_invokeSnap` and integrates a Starknet Window Object (SWO). +The SWO simplifies account management and signing, and enhances the experience of handling account states and transactions. +You interact with the [Account object](https://starknetjs.com/docs/API/classes/Account) in the SWO for operations. + +The following table lists the core functionalities that each integration option supports: + +| Functionality | `get-starknet` | `wallet_invokeSnap` | +|---------------|----------------|---------------------| +| Create an account | | [`starkNet_createAccount`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_createAccount) | +| Estimate a fee | [`estimateFeeBulk`](https://starknetjs.com/docs/API/classes/Account/#estimatefeebulk) | [`starkNet_estimateFee`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_estimateFee) | +| Estimate the account deploy fee | [`estimateAccountDeployFee`](https://starknetjs.com/docs/API/classes/Account/#estimateaccountdeployfee) | [`starkNet_estimateAccountDeployFee`](../../../reference/non-evm-apis/starknet-snap-api.md#starknet_estimateaccountdeployfee) | +| Extract the public key | [`getPublicKey`](https://starknetjs.com/docs/api/classes/Signer/#getpubkey) | [`starkNet_extractPublicKey`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_extractPublicKey) | +| Get an ERC20 token balance | [`callContract`](http://starknetjs.com/docs/API/classes/Provider/#callcontract) | [`starkNet_getErc20TokenBalance`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_getErc20TokenBalance) | +| Recover an account address | [`getAddress`](https://github.com/starknet-io/get-starknet/blob/ff37390b25b8368ebeb5f2323e2d8826964b41ae/packages/core/src/StarknetWindowObject.ts#L95) | [`starkNet_recoverAccounts`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_recoverAccounts) | +| Get transaction status | [`getTransactionStatus`](https://starknetjs.com/docs/API/classes/Account/#gettransactionstatus) | [`starkNet_getTransactionStatus`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_getTransactionStatus) | +| Sign a message | [`signMessage`](https://starknetjs.com/docs/API/classes/Signer#signmessage) | [`starkNet_signMessage`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_signMessage) | +| Sign a transaction | [`signTransaction`](https://starknetjs.com/docs/API/classes/Signer#signtransaction) | [`starkNet_signTransaction`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_signTransaction) | +| Sign eclare Transaction | [`signDeclareTransaction`](https://starknetjs.com/docs/API/classes/Signer#signdeclaretransaction) | [`starkNet_signDeclareTransaction`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_signDeclareTransaction) | +| Execute a transaction | [`execute`](https://starknetjs.com/docs/API/classes/Account/#execute) | [`starkNet_executeTxn`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_executeTxn) | +| Add an ERC20 token | [`watchAsset`](https://github.com/starknet-io/get-starknet/blob/ff37390b25b8368ebeb5f2323e2d8826964b41ae/packages/core/src/StarknetWindowObject.ts#L58) | [`starkNet_addErc20Token`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_addErc20Token) | +| Switch networks | [`switchNetwork`](https://github.com/starknet-io/get-starknet/blob/ff37390b25b8368ebeb5f2323e2d8826964b41ae/packages/core/src/StarknetWindowObject.ts#L58) | [`starkNet_switchNetwork`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_switchNetwork) | +| Get the current network | [`getChainId`](https://starknetjs.com/docs/API/classes/Provider#getchainid) | [`starkNet_getCurrentNetwork`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_getCurrentNetwork) | +| Declare a contract | [`declareContract`](https://starknetjs.com/docs/API/classes/Account/#declarecontract) | [`starkNet_declareContract`](../../../reference/non-evm-apis/starknet-snap-api.md#starkNet_declareContract) | \ No newline at end of file diff --git a/wallet/how-to/use-non-evm-networks/starknet/manage-starknet-accounts.md b/wallet/how-to/use-non-evm-networks/starknet/manage-starknet-accounts.md new file mode 100644 index 0000000000..b72769c55b --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/manage-starknet-accounts.md @@ -0,0 +1,412 @@ +--- +description: Manage Starknet accounts in MetaMask. +sidebar_position: 2 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Manage Starknet accounts + +You can manage Starknet accounts in MetaMask using the +[`get-starknet`](https://github.com/starknet-io/get-starknet) library or the +[`wallet_invokeSnap`](/snaps/reference/wallet-api-for-snaps/#wallet_invokesnap) JSON-RPC method. + +:::note Notes + +- Account creation in Starknet is handled by the wallet provider. + As a dapp developer, you do not create accounts directly. + Instead, you can guide users to [create an account](connect-to-starknet.md) with MetaMask. +- Currently, the Starknet Snap doesn't support multiple Starknet accounts. + +::: + +## Prerequisites + +[Connect to Starknet](connect-to-starknet.md) from your dapp. + +## Display account information + +After a user connects to their Starknet account in MetaMask, you can display the account details. +The following example displays the account address: + + + + + ```javascript + const showAccountInfo = async () => { + const account = await connectStarknetAccount(); + if (account) { + document.getElementById("accountAddress").innerText = `Account Address: ${account}`; + } + }; + ``` + + + + + ```javascript + const showAccountInfo = async () => { + if (typeof window.ethereum !== "undefined" && window.ethereum.isMetaMask) { + try { + // Invoke the Starknet Snap to get account information. + const response = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@starknet-snap/snap", + request: { + method: "starknet_getAccounts" + } + } + }); + + if (response && response.length > 0) { + const account = response[0]; // Get the first account. + document.getElementById("accountAddress").innerText = `Account Address: ${account.address}`; + } else { + document.getElementById("accountAddress").innerText = "No Starknet account found"; + } + } catch (error) { + console.error("Error fetching Starknet account:", error); + document.getElementById("accountAddress").innerText = "Error fetching account information"; + } + } else { + document.getElementById("accountAddress").innerText = "MetaMask not detected or Snaps not supported"; + } + }; + + // Call the function when needed + showAccountInfo(); + ``` + + + + +## Retrieve the connected account + +You can retrieve and display a user's connected Starknet account. +The following example displays the connected account address if available, and displays buttons to +connect or disconnect the account. + + + + + ```javascript + import { useStarknet, useConnectors } from "@starknet-react/core"; + import { useState, useEffect } from "react"; + + function AccountDisplay() { + const { account } = useStarknet(); + const { available, connect, disconnect } = useConnectors(); + const [accountAddress, setAccountAddress] = useState(); + + useEffect(() => { + setAccountAddress(account?.address); + }, [account]); + + return ( +
+ {accountAddress ? ( +

Connected Account: {accountAddress}

+ ) : ( +

No account connected

+ )} + {available.map((connector) => ( + + ))} + {account && ( + + )} +
+ ); + } + ``` + +
+ + + ```javascript + import React, { useState, useEffect } from "react"; + + const STARKNET_SNAP_ID = "npm:@starknet-snap/snap"; + + function AccountDisplay() { + const [accountAddress, setAccountAddress] = useState(); + const [isConnected, setIsConnected] = useState(false); + const [error, setError] = useState(null); + + const connectToSnap = async () => { + if (typeof window.ethereum !== "undefined" && window.ethereum.isMetaMask) { + try { + // Request permission to access the Snap + await window.ethereum.request({ + method: "wallet_requestSnaps", + params: { [STARKNET_SNAP_ID]: {} } + }); + setIsConnected(true); + fetchAccount(); + } catch (err) { + console.error("Error connecting to Starknet Snap:", err); + setError("Failed to connect to Starknet Snap"); + } + } else { + setError("MetaMask not detected or Snaps not supported"); + } + }; + + const disconnectFromSnap = async () => { + setAccountAddress(undefined); + setIsConnected(false); + }; + + const fetchAccount = async () => { + if (typeof window.ethereum !== "undefined" && window.ethereum.isMetaMask) { + try { + const response = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: STARKNET_SNAP_ID, + request: { + method: "starknet_getAccounts" + } + } + }); + + if (response && response.length > 0) { + setAccountAddress(response[0].address); + } else { + setError("No Starknet account found"); + } + } catch (err) { + console.error("Error fetching Starknet account:", err); + setError("Failed to fetch account information"); + } + } + }; + + useEffect(() => { + if (isConnected) { + fetchAccount(); + } + }, [isConnected]); + + return ( +
+ {accountAddress ? ( +

Connected Account: {accountAddress}

+ ) : ( +

No account connected

+ )} + {!isConnected ? ( + + ) : ( + + )} + {error &&

{error}

} +
+ ); + } + + export default AccountDisplay; + ``` + +
+
+ + +## Manage account transactions + +You can manage a user's Starknet account transactions. +The following example invokes a specific function on a Starknet smart contract, handles wallet +connection and transaction submission, and logs the result or any errors: + + + + +```javascript +const invokeStarknetContract = async () => { + try { + const starknet = getStarknet(); + await starknet.enable(); // Make sure the wallet is enabled. + + const contractAddress = "0xYourContractAddress"; // Replace with your contract address. + const entrypoint = "function_name"; // The function you want to call. + const calldata = [/* your function arguments */]; // Replace with calldata + + const result = await starknet.invoke({ + contractAddress: contractAddress, + entrypoint: entrypoint, + calldata: calldata + }); + + console.log("Transaction result: ", result); + } catch (error) { + console.error("Error invoking contract:", error); + } +}; +``` + + + + + ```javascript + const invokeStarknetContract = async () => { + if (typeof window.ethereum !== "undefined" && window.ethereum.isMetaMask) { + try { + const contractAddress = "0xYourContractAddress"; // Replace with your contract address. + const entrypoint = "function_name"; // The function you want to call. + const calldata = [/* your function arguments */]; + + const result = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@starknet-snap/snap", + request: { + method: "starkNet_sendTransaction", + params: { + contractAddress: contractAddress, + contractFuncName: entrypoint + contractCallData: calldata.join(","), + senderAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + maxFee: "1000000000000000", // + } + } + } + }); + + console.log("Transaction result: ", result); + } catch (error) { + console.error("Error invoking contract:", error); + } + } else { + console.error("MetaMask not detected or Snaps not supported"); + } + }; + ``` + + + + +## Handle account changes and disconnections + +You can handle account changes and disconnections. +Use the following component at the top level of your dapp to handle account changes globally: + + + + + ```javascript + import { getStarknet } from "get-starknet"; + import { useEffect, useState } from "react"; + + function AccountChangeHandler() { + const [account, setAccount] = useState(null); + + useEffect(() => { + const starknet = getStarknet(); + + const handleAccountsChanged = (accounts: string[]) => { + console.log("Accounts changed:", accounts); + setAccount(accounts[0] || null); + }; + + const handleDisconnect = () => { + console.log("Disconnected from wallet"); + setAccount(null); + }; + + if (starknet) { + starknet.on("accountsChanged", handleAccountsChanged); + starknet.on("networkChanged", handleDisconnect); + + // Initial account setup. + starknet.enable().then((accounts: string[]) => { + setAccount(accounts[0] || null); + }); + + return () => { + starknet.off("accountsChanged", handleAccountsChanged); + starknet.off("networkChanged", handleDisconnect); + }; + } + }, []); + + return ( +
+ {account ? ( +

Connected Account: {account}

+ ) : ( +

No account connected

+ )} +
+ ); + } + + export default AccountChangeHandler; + ``` +
+ + + ```javascript + import React, { useEffect, useState } from "react"; + + const STARKNET_SNAP_ID = "npm:@starknet-snap/snap"; + + function AccountChangeHandler() { + const [account, setAccount] = useState(null); + + const fetchAccount = async () => { + if (typeof window.ethereum !== "undefined" && window.ethereum.isMetaMask) { + try { + const response = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: STARKNET_SNAP_ID, + request: { + method: "starknet_getAccounts" + } + } + }); + + if (response && response.length > 0) { + setAccount(response[0].address); + } else { + setAccount(null); + } + } catch (error) { + console.error("Error fetching Starknet account:", error); + setAccount(null); + } + } else { + console.error("MetaMask not detected or Snaps not supported"); + setAccount(null); + } + }; + + useEffect(() => { + fetchAccount(); + + // Retrieve account changes every 5 seconds. + const intervalId = setInterval(fetchAccount, 5000); + + return () => clearInterval(intervalId); + }, []); + + return ( +
+ {account ? ( +

Connected Account: {account}

+ ) : ( +

No account connected

+ )} +
+ ); + } + + export default AccountChangeHandler; + ``` + +
+
diff --git a/wallet/how-to/use-non-evm-networks/starknet/manage-starknet-networks.md b/wallet/how-to/use-non-evm-networks/starknet/manage-starknet-networks.md new file mode 100644 index 0000000000..25d6118bcc --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/manage-starknet-networks.md @@ -0,0 +1,140 @@ +--- +description: Manage Starknet networks in MetaMask. +sidebar_position: 3 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Manage Starknet networks + +You can detect a user's Starknet network and prompt them to switch Starknet networks in MetaMask, +using the +[`get-starknet`](https://github.com/starknet-io/get-starknet) library or the +[`wallet_invokeSnap`](/snaps/reference/wallet-api-for-snaps/#wallet_invokesnap) JSON-RPC method. + +## Prerequisites + +[Connect to Starknet](connect-to-starknet.md) from your dapp. + +## Detect a user's network + +Detect the Starknet network a user is currently connected to using the following: + + + + + ```javascript + const checkCurrentNetwork = () => { + const starknet = getStarknet(); + const currentNetwork = starknet.provider.rpcUrl; + console.log("Currently connected to:", currentNetwork); + return currentNetwork; + }; + ``` + + + + + ```javascript + const checkCurrentNetwork = async () => { + if (typeof window.ethereum !== "undefined" && window.ethereum.isMetaMask) { + try { + const response = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starknet_getChainId" + } + } + }); + + let networkName; + switch (response) { + case "0x534e5f4d41494e": + networkName = "Mainnet"; + break; + case "0x534e5f5345504f4c4941": + networkName = "Sepolia Testnet"; + break; + default: + networkName = "Unknown Network"; + } + + console.log("Currently connected to:", networkName); + return response; // Returns the chain ID. + } catch (error) { + console.error("Error getting current Starknet network:", error); + throw error; + } + } else { + console.error("MetaMask not detected or Snaps not supported"); + throw new Error("MetaMask not detected or Snaps not supported"); + } + }; + + checkCurrentNetwork().then(chainId => { + console.log("Chain ID:", chainId); + }).catch(error => { + console.error("Error:", error); + }); + ``` + + + + +## Switch networks + +Starknet currently supports two public networks, Mainnet and Sepolia testnet. +Prompt users to switch between networks by setting the +[chain ID](../../../reference/non-evm-apis/starknet-snap-api.md#supported-networks) of the target network: + + + + + ```javascript + const switchChain = async (chainId: string) => { + try { + await wallet?.request({ + type: "wallet_switchStarknetChain", + params: { chainId: chainId }, + }); + console.log(`Switched to chainId: ${chainId}`); + } catch (e) { + console.error("Failed to switch chain:", e); + } + }; + ``` + + + + + ```javascript + const switchStarknetNetwork = async (chainId) => { + if (typeof window.ethereum !== "undefined" && window.ethereum.isMetaMask) { + try { + await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "wallet_switchStarknetChain", + params: { chainId: chainId } + } + } + }); + console.log(`Switched to Starknet network with chainId: ${chainId}`); + } catch (error) { + console.error("Error switching Starknet network:", error); + throw error; + } + } else { + console.error("MetaMask not detected or Snaps not supported"); + throw new Error("MetaMask not detected or Snaps not supported"); + } + }; + ``` + + + \ No newline at end of file diff --git a/wallet/how-to/use-non-evm-networks/starknet/send-starknet-transactions.md b/wallet/how-to/use-non-evm-networks/starknet/send-starknet-transactions.md new file mode 100644 index 0000000000..b92a252b87 --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/send-starknet-transactions.md @@ -0,0 +1,197 @@ +--- +description: Send Starknet transactions in MetaMask. +sidebar_position: 4 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Send Starknet transactions + +You can send Starknet transactions using the +[`get-starknet`](https://github.com/starknet-io/get-starknet) library or the +[`wallet_invokeSnap`](/snaps/reference/wallet-api-for-snaps/#wallet_invokesnap) JSON-RPC method. + +## Prerequisites + +[Connect to Starknet](connect-to-starknet.md) from your dapp. + +## Send a transaction + +Send a transaction using the `starknet.account.execute()` function: + + + + + ```javascript + const sendStarknetTransaction = async (wallet, contractAddress, entrypoint, calldata) => { + try { + if(wallet?.isConnected !== true){ + throw("Wallet not connected"); + } + + // Send the transaction. + const result = await wallet?.account?.execute({ + contractAddress: contractAddress, // The address of the contract. + entrypoint: entrypoint, // The function to call in the contract. + calldata: calldata // The parameters to pass to the function. + }); + console.log("Transaction successful:", result); + return result; + } catch (error) { + console.error("Error sending transaction:", error); + } + }; + ``` + + + + + ```javascript + const sendStarknetTransaction = async (contractAddress, contractFuncName, contractCallData, senderAddress, maxFee = null) => { + if (typeof window.ethereum === "undefined" || !window.ethereum.isMetaMask) { + throw new Error("MetaMask not detected or Snaps not supported"); + } + + try { + const response = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_sendTransaction", + params: { + contractAddress, + contractFuncName, + contractCallData, + senderAddress, + maxFee, + // chainId is optional, defaults to Starknet Sepolia testnet + } + } + } + }); + console.log("Transaction sent:", response); + return response; + } catch (error) { + console.error("Error sending transaction:", error); + throw error; + } + }; + ``` + + + + +## Simplified example + +The following is a full, simplified example of connecting to a Starknet account and sending a transaction: + + + + + ```javascript + import { connect } from "get-starknet"; + + const connectStarknetAccount = async () => { + const starknet = await connect(); + await starknet.enable(); // Prompts the user to connect their Starknet account using MetaMask + return starknet; + }; + + const sendStarknetTransaction = async (contractAddress, entrypoint, calldata) => { + try { + const starknet = await connectStarknetAccount(); // Ensure the account is connected + + // Send the transaction + const result = await starknet.account.execute({ + contractAddress: contractAddress, + entrypoint: entrypoint, + calldata: calldata + }); + + console.log("Transaction successful:", result); + return result; + } catch (error) { + console.error("Error sending transaction:", error); + } + }; + + const contractAddress = "0xYourContractAddress"; + const entrypoint = "your_function_name"; + const calldata = [/* your function arguments */]; + + sendStarknetTransaction(contractAddress, entrypoint, calldata); + ``` + + + + + ```javascript + const connectStarknetAccount = async () => { + if (typeof window.ethereum === "undefined" || !window.ethereum.isMetaMask) { + throw new Error("MetaMask not detected or Snaps not supported"); + } + + try { + await window.ethereum.request({ + method: "wallet_requestSnaps", + params: { + "npm:@consensys/starknet-snap": {} + } + }); + console.log("Starknet Snap connected"); + } catch (error) { + console.error("Error connecting to Starknet Snap:", error); + throw error; + } + }; + + const sendStarknetTransaction = async (contractAddress, contractFuncName, contractCallData, senderAddress, maxFee = null) => { + try { + await connectStarknetAccount(); + + const requestParams = { + contractAddress, + contractFuncName, + contractCallData, + senderAddress + }; + + if (maxFee) { + requestParams.maxFee = maxFee; // Include maxFee only if it's provided. + } + + const response = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_sendTransaction" + params: requestParams + } + } + }); + + console.log("Transaction sent:", response); + return response; + } catch (error) { + console.error("Error sending transaction:", error); + throw error; + } + }; + + // Example usage + const contractAddress = "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"; + const contractFuncName = "transfer"; + const contractCallData = ["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", "1000"]; + const senderAddress = "0xb60e8dd61c5d32be8058bb8eb970870f07233155"; + const maxFee = "1000000000000000"; // Optional + + sendStarknetTransaction(contractAddress, contractFuncName, contractCallData, senderAddress, maxFee) + .then(result => console.log("Transaction result:", result)) + .catch(error => console.error("Transaction error:", error)); + ``` + + + \ No newline at end of file diff --git a/wallet/how-to/use-non-evm-networks/starknet/sign-starknet-data.md b/wallet/how-to/use-non-evm-networks/starknet/sign-starknet-data.md new file mode 100644 index 0000000000..f1432b4983 --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/sign-starknet-data.md @@ -0,0 +1,100 @@ +--- +description: Sign Starknet transactions in MetaMask. +sidebar_position: 5 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Sign Starknet transactions + +You can sign Starknet transactions using the +[`get-starknet`](https://github.com/starknet-io/get-starknet) library or the +[`wallet_invokeSnap`](/snaps/reference/wallet-api-for-snaps/#wallet_invokesnap) JSON-RPC method. + +## Prerequisites + +[Connect to Starknet](connect-to-starknet.md) from your dapp. + +## Sign a transaction + +You can sign a transaction using the `wallet.account.signer.signTransaction` function: + + + + + ```typescript + const signStarknetTransaction = async (wallet, contractAddress, entrypoint, calldata) => { + try { + if(wallet?.isConnected !== true){ + throw("Wallet not connected"); + } + + // Send the transaction. + const result = await wallet?.account?.signer.signTransaction({ + contractAddress: contractAddress, // The address of the contract. + entrypoint: entrypoint, // The function to call in the contract. + calldata: calldata // The parameters to pass to the function. + }); + console.log("Transaction signed successfully:", result); + return result; + } catch (error) { + console.error("Error signing transaction:", error); + } + }; + ``` + + + + ```typescript + const signStarknetTransactionWithSnap = async (contractAddress, entrypoint, calldata) => { + try { + if (typeof window.ethereum === "undefined" || !window.ethereum.isMetaMask) { + throw new Error("MetaMask not detected or Snaps not supported"); + } + + // Connect to the Starknet Snap if it's not already connected. + await window.ethereum.request({ + method: "wallet_requestSnaps", + params: { + "npm:@consensys/starknet-snap": {} + } + }); + console.log("Starknet Snap connected"); + + // Use the wallet_invokeSnap method to sign the transaction. + const response = await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_signTransaction", + params: { + contractAddress, // The address of the contract. + entrypoint, // The function to call in the contract. + calldata // The parameters to pass to the function (as an array). + } + } + } + }); + + console.log("Transaction signed successfully:", response); + return response; + } catch (error) { + console.error("Error signing transaction:", error); + throw error; + } + }; + + // Example usage: + const contractAddress = "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"; + const entrypoint = "transfer"; + const calldata = ["0xRecipientAddress", "1000"]; + + signStarknetTransactionWithSnap(contractAddress, entrypoint, calldata) + .then(result => console.log("Signed transaction result:", result)) + .catch(error => console.error("Transaction error:", error)); + ``` + + + \ No newline at end of file diff --git a/wallet/how-to/use-non-evm-networks/starknet/troubleshoot.md b/wallet/how-to/use-non-evm-networks/starknet/troubleshoot.md new file mode 100644 index 0000000000..0883f39ba0 --- /dev/null +++ b/wallet/how-to/use-non-evm-networks/starknet/troubleshoot.md @@ -0,0 +1,165 @@ +--- +description: Troubleshoot common Starknet issues. +sidebar_position: 7 +toc_max_heading_level: 4 +--- + +# Troubleshoot + +This guide addresses issues that might occur when connecting your dapp to the Starknet Snap in MetaMask. + +## Connection issues + +When using `get-starknet`, the library automatically handles detecting and connecting to MetaMask, +and adding the Starknet Snap. +If you're using `wallet_invokeSnap` directly, you might need to manage these processes manually. + +### Detect MetaMask + +When using `wallet_invokeSnap`, use the following function to detect if MetaMask is installed: + +```typescript +async function detectMetamaskSupport(windowObject: Window & typeof globalThis): Promise { + const provider = await waitForMetaMaskProvider(windowObject, { retries: 3 }); + return provider; +} +``` + +This function uses the [`waitForMetaMaskProvider`](#waitformetamaskprovider) helper function, which +attempts to detect the MetaMask provider three times. + +In the event MetaMask is not installed, for example `isMetaMaskInstallRequired=true`, you can prompt +the user to install MetaMask using the following: + +```typescript +function checkAndPromptForMetaMask() { + const isMetaMaskInstalled = typeof window.ethereum !== "undefined" && window.ethereum.isMetaMask; + + if (!isMetaMaskInstalled) { + console.log("MetaMask is not installed. Prompting user to install."); + + // Update UI to inform the user. + const messageElement = document.getElementById("metamask-message") || document.createElement("div"); + messageElement.id = "metamask-message"; + messageElement.innerHTML = ` +

MetaMask is required to use this dapp. Please install MetaMask to continue.

+ + `; + document.body.appendChild(messageElement); + + // Add click event to the install button. + document.getElementById("install-metamask").addEventListener("click", () => { + window.open("https://metamask.io/download.html", "_blank"); + }); + } else { + console.log("MetaMask is installed. Proceeding with this dapp."); + } +} + +// Call this function when your dapp initializes. +checkAndPromptForMetaMask(); +``` + +### Verify Snap support + +After detecting MetaMask, verify if it supports Snaps: + +```typescript +const isSupportSnap = async (provider: any): Promise => { + try { + await provider.request({ + method: "wallet_getSnaps", + }); + return true; + } catch { + return false; + } +}; +``` + +If MetaMask is installed but the Snap is not, use the following code to prompt the user to install the Snap: + +```typescript +async function installSnap(provider: MetaMaskProvider, snapId: string, snapVersion: string) { + try { + await provider.request({ + method: "wallet_requestSnaps", + params: { + [snapId]: { version: snapVersion }, + }, + }); + console.log("Snap installed successfully"); + } catch (error) { + console.error("Failed to install Snap:", error); + // Handle the error (for example, user rejected installation). + } +} +``` + +### Handle user rejection + +Users can reject the prompt to add the Snap, resulting in a 4001 error. +Provide an error message to ensure users have clear guidance on next steps. +For example: + +```javascript +function handleConnectionError(error) { + if (error.code === 4001) { + console.log("User rejected the request to add the Starknet Snap"); + displayUserMessage("To proceed, you need to add the Starknet Snap to MetaMask. Please try connecting again."); + } else { + console.error("An error occurred while connecting to Starknet Snap:", error); + displayUserMessage("An error occurred. Please ensure MetaMask is installed and try again."); + } +} + +function displayUserMessage(message) { + // Update your UI to display the message to the user. + // For example: + // document.getElementById("status-message").textContent = message; +} +``` + +### Helper functions + +The following helper functions support the detection process. +This is useful for troubleshooting issues that might occur when using the `wallet_invokeSnap` method. + +#### `isMetaMaskProvider` + +This function checks if a given object is a valid `MetaMaskProvider`: + +```typescript +function isMetaMaskProvider(obj: unknown): obj is MetaMaskProvider { + return ( + obj !== null && + typeof obj === "object" && + obj.hasOwnProperty("isMetaMask") && + obj.hasOwnProperty("request") + ); +} +``` + +#### `detectMetaMaskProvider` + +This function detects a MetaMask provider by listening for the `eip6963:announceProvider` event: + +```typescript +function detectMetaMaskProvider( + windowObject: Window & typeof globalThis, + { timeout = 3000 } = {}, +): Promise { +} +``` + +#### `waitForMetaMaskProvider` + +This function waits for a MetaMask provider to be detected and retries the operation if needed: + +```typescript +async function waitForMetaMaskProvider( + windowObject: Window & typeof globalThis, + { timeout = 1000, retries = 0 } = {}, +): Promise { +} +``` diff --git a/wallet/reference/non-evm-apis/starknet-snap-api.md b/wallet/reference/non-evm-apis/starknet-snap-api.md new file mode 100644 index 0000000000..8dd284ef3a --- /dev/null +++ b/wallet/reference/non-evm-apis/starknet-snap-api.md @@ -0,0 +1,868 @@ +--- +description: See the Starknet Snap API reference. +sidebar_position: 1 +--- + +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +# Starknet Snap API + +When connected to the [Starknet Snap](../../how-to/use-non-evm-networks/starknet/index.md), dapps +can use the Starknet Snap API to interact with users' Starknet accounts (for example, to send transactions). + +Currently, the [`get-starknet`](https://github.com/starknet-io/get-starknet) library only supports the +following Starknet Snap API methods: + +- [`starkNet_extractPublicKey`](#starknet_extractpublickey) +- [`starkNet_signMessage`](#starknet_signmessage) +- [`starkNet_upgradeAccContract`](#starknet_upgradeacccontract) +- [`starkNet_verifyMessage`](#starknet_verifymessage) + +The examples on this page use the +[`wallet_invokeSnap`](/snaps/reference/wallet-api-for-snaps/#wallet_invokesnap) JSON-RPC method, +which supports all Starknet Snap API methods. + +:::note + +You can also communicate with the Starknet network using the +[Starknet API](/services/reference/starknet). + +::: + +## Supported networks + +Starknet currently supports two public networks. +Use these networks' chain IDs with the Starknet Snap API methods. + +| Network | Chain ID (Hexadecimal) | +|-------------------|--------------------------| +| Mainnet | `0x534e5f4d41494e` | +| Testnet (Sepolia) | `0x534e5f5345504f4c4941` | + +## API methods + +### `starkNet_createAccount` + +Deploys an account contract. + +#### Parameters + +- `addressIndex`: `integer` - (Optional) Specific address index of the derived key in + [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). +- `deploy`: `boolean` - (Optional) Indicate whether to include send the deploy transaction for the + account contract. + The default is `false`. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The response from Starknet's `gateway/add_transaction` API endpoint. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_createAccount", + "params": { + "addressIndex": 1, + "deploy": true, + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +{ + "transaction_hash": "0x05a56e2d52c817161883f50c441c3228cfe54d9f84b5b5b8b1c8b8e0e6f7e6d8", + "address": "0xb60e8dd61c5d32be8058bb8eb970870f07233155" +} +``` + + + + +### `starkNet_displayPrivateKey` + +Extracts the private key from the deployed Starknet account and displays it in MetaMask. + +#### Parameters + +- `userAddress`: `string` - Address of the account contract. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +Always returns `null` for security reasons. +The private key is only shown in the MetaMask pop-up window. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_displayPrivateKey", + params: { + userAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +null +``` + + + + +### `starkNet_estimateAccountDeployFee` + +Gets the estimated gas fee for deploying an account contract. + +#### Parameters + +- `addressIndex`: `integer` - (Optional) Specific address index of the derived key in + [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The response from Starknet's `feeder_gateway/estimate_fee` API endpoint. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_estimateAccountDeployFee", + params: { + addressIndex: 0, + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +{ + "suggestedMaxFee": "1000000000000000", + "overallFee": "900000000000000", + "gasConsumed": "1000000", + "gasPrice": "1000000000", + "unit": "wei", + "includeDeploy": true +} +``` + + + + +### `starkNet_estimateFee` + +Gets the estimated gas fee for calling a method on any contract. + +#### Parameters + +- `contractAddress`: `string` - Address of the target contract. +- `contractFuncName`: `string` - Target function name of the contract. +- `contractCallData`: `string` - (Optional) Call data for the target function with `,` as a separator. +- `senderAddress`: `string` - Address of the sender. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The response from Starknet's `feeder_gateway/estimate_fee` API endpoint. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_estimateFee", + params: { + contractAddress: "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", + contractFuncName: "transfer", + contractCallData: "0x456...,0x789...,100", + senderAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +{ + "suggestedMaxFee": "1000000000000000", + "overallFee": "900000000000000", + "gasConsumed": "1000000", + "gasPrice": "1000000000", + "unit": "wei", + "includeDeploy": false +} +``` + + + + +### `starkNet_extractPublicKey` + +:::note + +This method is supported by the `get-starknet` library. + +::: + +Extracts the public key from a Starknet account address. + +#### Parameters + +- `userAddress`: `string` - Address of the account contract. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The public key of the given account address (can be different from the actual signer). + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_extractPublicKey", + params: { + userAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +"0x04bfcab3b7ca7e8b3f3b62b2f7f77e9e4b68080bbf8f0f4a1c8f890864d2c7c1d3c45d8b2e3f5f1c27dfeea4c2f5733e90bfc7484e2a690aa9b8ac4559d2e6a8d7" +``` + + + + +### `starkNet_getErc20TokenBalance` + +Gets the user's current balance of an ERC-20 token. + +#### Parameters + +- `tokenAddress`: `string` - Address of the ERC-20 token contract. +- `userAddress`: `string` - Address of the user account. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The latest and pending token balance in hexadecimal. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_getErc20TokenBalance", + params: { + tokenAddress: "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", + userAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +{ + "balancePending": "0x3e8", + "balanceLatest": "0x3e8", +} +``` + + + + +### `starkNet_getStoredUserAccounts` + +Gets a list of stored user accounts that are either initialized or initializing. + +#### Parameters + +`chainId`: `string` - (Optional) ID of the target Starknet network. +The default is the Starknet Sepolia testnet. + +#### Returns + +The list of the stored user accounts. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_getStoredUserAccounts", + params: { + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +[ + { + "address": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "addressIndex": 0, + "publicKey": "0x04bfcab3b7ca7e8b3f3b62b2f7f77e9e4b68080bbf8f0f4a1c8f890864d2c7c1d3c45d8b2e3f5f1c27dfeea4c2f5733e90bfc7484e2a690aa9b8ac4559d2e6a8d7", + "addressSalt": "0x789...", + "deployTxnHash": "0x05a56e2d52c817161883f50c441c3228cfe54d9f84b5b5b8b1c8b8e0e6f7e6d8", + "derivationPath": "m/44'/9004'/0'/0/0", + "chainId": "0x534e5f5345504f4c4941" + }, + // ... more accounts +] +``` + + + + +### `starkNet_getTransactions` + +Gets the transaction records from a sender address. + +#### Parameters + +- `senderAddress`: `string` - Address of the sender. +- `contractAddress`: `string` - (Optional) Address of the called contract. +- `pageSize`: `integer` - (Optional) Page size when calling the Voyager get "api/txns" endpoint. + Options are `10`, `25`, and `50`. + The default is `10`. +- `txnsInLastNumOfDays`: `integer` - (Optional) Number of past days of transaction records to be + fetched from Voyager. + The default is `5`. +- `withDeployTxn`: `boolean` - (Optional) Indicates whether to include the deploy transaction of the + sender's account contract. + The default is `false`. +- `onlyFromState`: `boolean` - (Optional) Indicates whether to only retrieve transaction records + that are stored in Snap state, that is, those in `RECEIVED`, `PENDING`, `ACCEPTED_ON_L2`, or + `REJECTED` state. + The default is `false`. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The list of the transaction records. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_getTransactions", + params: { + senderAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + contractAddress: "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", + pageSize: 25, + txnsInLastNumOfDays: 7, + withDeployTxn: true, + onlyFromState: false, + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +[ + { + "txnHash": "0x05a56e2d52c817161883f50c441c3228cfe54d9f84b5b5b8b1c8b8e0e6f7e6d8", + "txnType": "invoke", + "senderAddress": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "contractAddress": "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", + "contractFuncName": "transfer", + "contractCallData": ["0x789...", "100"], + "status": "ACCEPTED_ON_L2", + "failureReason": null, + "eventIds": ["0xdef..."], + "timestamp": 1234567890, + "chainId": "0x534e5f5345504f4c4941" + }, + // ... more transactions +] +``` + + + + +### `starkNet_getTransactionStatus` + +Gets the status of a transaction. + +#### Parameters + +- `transactionHash`: `string` - Hash of the target transaction. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The [status](https://docs.starknet.io/architecture-and-concepts/network-architecture/transaction-life-cycle/) +of the transaction. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_getTransactionStatus", + params: { + transactionHash: "0x05a56e2d52c817161883f50c441c3228cfe54d9f84b5b5b8b1c8b8e0e6f7e6d8", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +"ACCEPTED_ON_L2" +``` + + + + +### `starkNet_getValue` + +Calls a `VIEW` method on any contract. + +#### Parameters + +- `contractAddress`: `string` - Address of the target contract. +- `contractFuncName`: `string` - Target function name of the contract. +- `contractCallData`: `string` - (Optional) Call data for the target function with `,` as a separator. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The response from Starknet's `feeder_gateway/call_contract` API endpoint. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_getValue", + params: { + contractAddress: "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", + contractFuncName: "balanceOf", + contractCallData: "0x456...", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +{ + "result": ["1000"] +} +``` + + + + +### `starkNet_recoverAccounts` + +Recovers deployed user accounts from the seed phrase of MetaMask based on +[BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). + +#### Parameters + +- `startScanIndex`: `integer` - (Optional) Starting address index of the derived key in + [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). + The default is `0`. +- `maxScanned`: `integer` - (Optional) Maximum number of addresses to scan during the recovery process. + The default is `1`. +- `maxMissed`: `integer` - (Optional) Maximum number of uninitialized addresses hit during the + recovery process. + The default is `1`. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The list of the scanned user accounts during the recovery process. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_recoverAccounts", + params: { + startScanIndex: 0, + maxScanned: 5, + maxMissed: 2, + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +[ + { + "address": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "addressIndex": 0, + "publicKey": "0x04bfcab3b7ca7e8b3f3b62b2f7f77e9e4b68080bbf8f0f4a1c8f890864d2c7c1d3c45d8b2e3f5f1c27dfeea4c2f5733e90bfc7484e2a690aa9b8ac4559d2e6a8d7", + "addressSalt": "0x789...", + "deployTxnHash": "0x05a56e2d52c817161883f50c441c3228cfe54d9f84b5b5b8b1c8b8e0e6f7e6d8", + "derivationPath": "m/44'/9004'/0'/0/0", + "chainId": "0x534e5f5345504f4c4941" + }, + // ... more accounts +] +``` + + + + +### `starkNet_sendTransaction` + +Signs and sends a transaction. + +#### Parameters + +- `contractAddress`: `string` - Address of the target contract. +- `contractFuncName`: `string` - Target function name of the contract. +- `contractCallData`: `string` - (Optional) Call data for the target function with `,` as a separator. +- `senderAddress`: `string` - Address of the sender. +- `maxFee`: `string` - (Optional) Maximum gas fee allowed from the sender. + If not specified, the maximum fee is automatically calculated. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The response from Starknet's `gateway/add_transaction` API endpoint. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_sendTransaction", + params: { + contractAddress: "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", + contractFuncName: "transfer", + contractCallData: "0x456...,0x789...,100", + senderAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + maxFee: "1000000000000000", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +{ + "transaction_hash": "0x05a56e2d52c817161883f50c441c3228cfe54d9f84b5b5b8b1c8b8e0e6f7e6d8" +} +``` + + + + +### `starkNet_signMessage` + +:::note +This method is supported by the `get-starknet` library. +::: + +Signs a typed data message. + +#### Parameters + +- `typedDataMessage`: `string` - JSON representation of the typed data to be signed. +- `signerAddress`: `string` - Address of the signer. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The signed hash of typed data. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_signMessage", + params: { + typedDataMessage: "{ ... }", + signerAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +"1234567890,9876543210" +``` + + + + +### `starkNet_upgradeAccContract` + +:::note + +This method is supported by the `get-starknet` library. + +::: + +Upgrades an account contract. + +#### Parameters + +- `contractAddress`: `string` - Address of the target contract. +- `maxFee`: `string` - (Optional) Maximum gas fee allowed from the sender. + If not specified, the maximum fee is automatically calculated. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +The response from Starknet's `gateway/call_contract` API endpoint. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_upgradeAccContract", + params: { + contractAddress: "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4", + maxFee: "1000000000000000", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +{ + "transaction_hash": "0xdef..." +} +``` + + + + +### `starkNet_verifyMessage` + +:::note + +This method is supported by the `get-starknet` library. + +::: + +Verifies a signed typed data message. + +#### Parameters + +- `typedDataMessage`: `string` - JSON representation of the original typed data message to be verified. +- `signerAddress`: `string` - Address of the signer. +- `signature`: `string` - Signature of the typed data message. +- `chainId`: `string` - (Optional) ID of the target Starknet network. + The default is the Starknet Sepolia testnet. + +#### Returns + +`true` if the signature is verified, `false` otherwise. + +#### Example + + + + +```js +await window.ethereum.request({ + method: "wallet_invokeSnap", + params: { + snapId: "npm:@consensys/starknet-snap", + request: { + method: "starkNet_verifyMessage", + params: { + typedDataMessage: "{ ... }", + signerAddress: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + signature: "1234567890,9876543210", + "chainId": "0x534e5f5345504f4c4941" + }, + }, + }, +}) +``` + + + + +```json +true +``` + + + diff --git a/wallet/reference/provider-api.md b/wallet/reference/provider-api.md index aa6b7220c1..5bb9026b6a 100644 --- a/wallet/reference/provider-api.md +++ b/wallet/reference/provider-api.md @@ -1,6 +1,6 @@ --- description: See the MetaMask Ethereum provider API reference. -sidebar_position: 3 +sidebar_position: 4 --- # Ethereum provider API