Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Starknet Snap docs #1509

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Draft

WIP: Starknet Snap docs #1509

wants to merge 13 commits into from

Conversation

joaniefromtheblock
Copy link
Contributor

@joaniefromtheblock joaniefromtheblock commented Aug 28, 2024

Description

Draft of Starknet Snap docs.

Issue(s) fixed

Fixes #1511
Fixes #1512
Fixes #1513
Fixes #1514
Fixes #1515
Fixes #1516
Fixes #1526

Preview

Checklist

Complete this checklist before merging your PR:

  • If this PR contains a major change to the documentation content, I have added an entry to the top of the "What's new?" page.
  • The proposed changes have been reviewed and approved by a member of the documentation team.

Copy link

vercel bot commented Aug 28, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
metamask-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Sep 19, 2024 6:37pm

@alexandratran alexandratran marked this pull request as draft August 28, 2024 19:42
@alexandratran alexandratran changed the title WIP: Starknet Snap Rough Skeleton WIP: Starknet Snap docs Sep 5, 2024

# Starknet

You can interact with users' Starknet accounts in MetaMask by installing the Starknet Snap.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better way to say this is, "by connecting to the Starknet Snap for MetaMask."

@Montoya
Copy link
Collaborator

Montoya commented Sep 6, 2024

Some notes on connect vs install:

  • We are moving away from using the term "install" with Snaps. We prefer "add" such as "add to MetaMask."
  • For the dapp, the primary action to initiate interacting with Starknet accounts is to connect to the Snap, just like a dapp connects with MetaMask to interact with Ethereum accounts. Whether the user has the Starknet Snap installed already is not important. If the user needs to install the Snap, they will be prompted to do so.
    • Despite this, we do need to explain that the user can reject the prompt to add the Snap to MetaMask and document what to expect (the response that the dapp will receive if the user rejects the request) and encourage the dapp to do something in that instance, like display a message to the user that they need to add the Snap to MetaMask in order to proceed.
    • Also, in terms of working with Starknet specifically, we may need to explain that a user will need to take some steps to set up a Starknet account before they can actually use it with the dapp, so the dapp should thoughtfully design that onboarding flow. Whether the user needs to add the Snap (and thus they will be completely new to Starknet) or they already have it but their account is not funded or deployed, the dapp should handle those scenarios.


## Connect using `get-starknet`

### 1. Add `get-starknet` to your project
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### 1. Add `get-starknet` to your project
### 0. Set up a React project
If you don't have an existing React project you can set it up as follow:
<Tabs>
<TabItem value="yarn" label="Yarn" default>
\```bash
yarn create react-app get-starknet-tutorial
\```
</TabItem>
<TabItem value="npm" label="npm">
\```bash
npm create react-app get-starknet-tutorial
\```
</TabItem>
</Tabs>
### 1. Add `get-starknet` to your project

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could give the command line on how to set up an empty react project.

Copy link
Contributor

@khanti42 khanti42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need some changes on api commented with "needs check" because the api changed. I will do a separate review for them.

wallet/reference/non-evm-apis/starknet-snap-api.md Outdated Show resolved Hide resolved
"params": {
"addressIndex": 1,
"deploy": true,
"chainId": "0x1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could provide here an existing chainId, maybe the testnet one ? Or make clear what the chain id should be at the beginning of the page.

</TabItem>
</Tabs>

## `starkNet_estimateAccountDeployFee`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs check

Copy link
Contributor Author

@joaniefromtheblock joaniefromtheblock Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khanti42 working on this time

</TabItem>
</Tabs>

## `starkNet_estimateFee`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khanti42 working on this time

wallet/reference/non-evm-apis/starknet-snap-api.md Outdated Show resolved Hide resolved

### Returns

The list of the stored user accounts.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two new optional return parameters in the account: upgradeRequired and deployRequired.

User accounts type is as follow :

export type AccContract = {
  addressSalt: string;
  publicKey: string; // in hex
  address: string; // in hex
  addressIndex: number;
  derivationPath: string;
  deployTxnHash: string; // in hex
  chainId: string; // in hex
  upgradeRequired?: boolean; // whether the account requires an upgrade to Cairo 1
  deployRequired?: boolean; // whether the account requires to be deployed
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khanti42 I have questions about this one (raised in chat)

</TabItem>
</Tabs>

## `starkNet_signMessage`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khanti42 working on this time

</TabItem>
</Tabs>

## `starkNet_verifyMessage`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khanti42 working on this time

Copy link
Contributor

@alexandratran alexandratran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some suggestions on the intro pages.

wallet/how-to/use-non-evm-networks/index.md Outdated Show resolved Hide resolved
wallet/how-to/use-non-evm-networks/index.md Outdated Show resolved Hide resolved
wallet/how-to/use-non-evm-networks/index.md Show resolved Hide resolved
wallet/how-to/use-non-evm-networks/index.md Show resolved Hide resolved
@@ -0,0 +1,9 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need a _category_.json file for this section because there is already an index.md file.

wallet/how-to/use-non-evm-networks/starknet/index.md Outdated Show resolved Hide resolved
wallet/how-to/use-non-evm-networks/starknet/index.md Outdated Show resolved Hide resolved
wallet/how-to/use-non-evm-networks/starknet/index.md Outdated Show resolved Hide resolved
wallet/how-to/use-non-evm-networks/starknet/index.md Outdated Show resolved Hide resolved
sidebar_position: 5
---

# Sign Starknet data
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@khanti42 thanks for all your feedback. Can you please add code to this one as well?


### Snap ID error

Ensure you're using the correct Snap ID for the StarkNet Snap. Incorrect IDs will result in failed connections.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Ensure you're using the correct Snap ID for the StarkNet Snap. Incorrect IDs will result in failed connections.
Ensure you're using the correct Snap ID for the StarkNet Snap. Incorrect IDs will result in failed connections.
The Starknet Snap ID is the name of the npm package of the snap: `@consensys/starknet-snap`.

Comment on lines +42 to +54
### Stale wallet data

If the wallet address or account information doesn't update after reconnection, always listen for account or network changes and handle them appropriately. Use event listeners:

```javascript
ethereum.on('accountsChanged', (accounts) => {
// Handle account change
});
ethereum.on('chainChanged', (chainId) => {
// Handle network change
});
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not apply to the snap we can remove this part.

Suggested change
### Stale wallet data
If the wallet address or account information doesn't update after reconnection, always listen for account or network changes and handle them appropriately. Use event listeners:
```javascript
ethereum.on('accountsChanged', (accounts) => {
// Handle account change
});
ethereum.on('chainChanged', (chainId) => {
// Handle network change
});
```

Comment on lines +8 to +35
## 1. Connection issues

### Wallet connection fails or doesn't respond.

Ensure that MetaMask is installed and the StarkNet Snap is properly set up. You can check if the Snap is available using:

```javascript
const availableWallets = getAvailableWallets();
if (!availableWallets.some(wallet => wallet.type === 'snap')) {
alert('Please install StarkNet Snap in MetaMask to proceed.');
}
```

### The `connect()` function returns null or undefined.

Verify that the Snap is installed and MetaMask has granted permission for the dapp to connect. Always include error handling in the connect method to manage issues:

```javascript
try {
const res = await connect();
if (!res) {
console.log('No wallet connected');
}
} catch (error) {
console.error('Error connecting to wallet:', error);
}
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## 1. Connection issues
### Wallet connection fails or doesn't respond.
Ensure that MetaMask is installed and the StarkNet Snap is properly set up. You can check if the Snap is available using:
```javascript
const availableWallets = getAvailableWallets();
if (!availableWallets.some(wallet => wallet.type === 'snap')) {
alert('Please install StarkNet Snap in MetaMask to proceed.');
}
```
### The `connect()` function returns null or undefined.
Verify that the Snap is installed and MetaMask has granted permission for the dapp to connect. Always include error handling in the connect method to manage issues:
```javascript
try {
const res = await connect();
if (!res) {
console.log('No wallet connected');
}
} catch (error) {
console.error('Error connecting to wallet:', error);
}
```
When using get-starknet MetaMask detection, connection and starknet snap installation is handled automatically.
In case you are using `invokeSnaps` directly then this needs to be handled manually.
You need to check first that MetaMask is installed :
```typescript
interface MetaMaskProvider {
isMetaMask: boolean;
request(options: { method: string }): Promise<void>;
}
declare global {
interface Window {
ethereum?: MetaMaskProvider;
}
}
/**
* Detects if MetaMask is installed and supports Snaps by invoking the 'wallet_getSnaps' method.
*
* @param {any} provider - The provider object, typically obtained from MetaMask.
* @returns {Promise<boolean>} - A promise that resolves to `true` if the provider supports Snaps, and `false` otherwise.
*/
const isSupportSnap = async (provider: any): Promise<boolean> => {
try {
await provider.request({
method: 'wallet_getSnaps',
});
return true;
} catch {
return false;
}
};
/**
* Type guard function to check if a given object is a valid MetaMaskProvider.
*
* @param {unknown} obj - The object to check.
* @returns {boolean} - `true` if the object is a MetaMask provider, `false` otherwise.
*/
function isMetaMaskProvider(obj: unknown): obj is MetaMaskProvider {
return (
obj !== null &&
typeof obj === 'object' &&
obj.hasOwnProperty('isMetaMask') &&
obj.hasOwnProperty('request')
);
}
/**
* Detects a MetaMask provider by listening for the 'eip6963:announceProvider' event.
*
* @param {Window & typeof globalThis} windowObject - The window object used to access global browser features.
* @param {Object} options - Optional parameters, including a timeout for the detection process.
* @param {number} [options.timeout=3000] - The time to wait (in milliseconds) for the provider to announce itself.
* @returns {Promise<MetaMaskProvider | null>} - A promise that resolves to a MetaMaskProvider object if detected, or `null` if no provider is found.
*/
function detectMetaMaskProvider(
windowObject: Window & typeof globalThis,
{ timeout = 3000 } = {},
): Promise<MetaMaskProvider | null> {
let handled = false;
return new Promise<MetaMaskProvider | null>((resolve) => {
const handleEIP6963Provider = (event: CustomEvent) => {
const { info, provider } = event.detail;
if (
['io.metamask', 'io.metamask.flask'].includes(info.rdns) &&
isMetaMaskProvider(provider)
) {
resolve(provider);
handled = true;
}
};
if (typeof windowObject.addEventListener === 'function') {
windowObject.addEventListener(
'eip6963:announceProvider',
(event: Event) => {
handleEIP6963Provider(event as CustomEvent);
},
);
}
setTimeout(() => {
if (!handled) {
resolve(null);
}
}, timeout);
if (typeof windowObject.dispatchEvent === 'function') {
windowObject.dispatchEvent(new Event('eip6963:requestProvider'));
}
});
}
/**
* Waits for a MetaMask provider to be detected, retrying if necessary.
*
* @param {Window & typeof globalThis} windowObject - The window object used to access global browser features.
* @param {Object} options - Optional parameters, including timeout and retries.
* @param {number} [options.timeout=1000] - The time (in milliseconds) to wait for each detection attempt.
* @param {number} [options.retries=0] - The number of retry attempts if no provider is detected.
* @returns {Promise<MetaMaskProvider | null>} - A promise that resolves to a MetaMaskProvider object if detected, or `null` if no provider is found.
*/
async function waitForMetaMaskProvider(
windowObject: Window & typeof globalThis,
{ timeout = 1000, retries = 0 } = {},
): Promise<MetaMaskProvider | null> {
return detectMetaMaskProvider(windowObject, { timeout })
.catch(function () {
return null;
})
.then(function (provider) {
if (provider || retries === 0) {
return provider;
}
return waitForMetaMaskProvider(windowObject, {
timeout,
retries: retries - 1,
});
});
}
/**
* Detects if MetaMask is installed by calling the waitForMetaMaskProvider function with retries.
*
* @param {Window & typeof globalThis} windowObject - The window object used to access global browser features.
* @returns {Promise<MetaMaskProvider | null>} - A promise that resolves to a MetaMaskProvider object if MetaMask is detected, or `null` otherwise.
*/
async function detectMetamaskSupport(windowObject: Window & typeof globalThis): Promise<MetaMaskProvider | null> {
const provider = await waitForMetaMaskProvider(windowObject, { retries: 3 });
return provider;
}
```
This can be used as follow to check for Metamask Snap Support. This will check for MetaMask presence, and the support of Snap in the installed MetaMask version if any. If there is no MetaMask installed or the version of MetaMask does not support snap
```typescript
let isMetaMaskInstallRequired = false;
let provider = null;
try {
provider = await detectMetamaskSupport(window);
// Use the new detection method
if (provider && (await isSupportSnap(provider))) {
isMetaMaskInstallRequired = provider === null;
} else {
isMetaMaskInstallRequired = true;
}
} catch (err) {
isMetaMaskInstallRequired = true;
}
```
In case MetaMask is not installed (e.g. `isMetaMaskInstallRequired=true` we can prompt the user to install MetaMask.
In case MetaMask is installed, we can prompt the user to install the Snap
```typescript
provider
.request({
method: 'wallet_requestSnaps',
params: {
[snapId]: { version: snapVersion },
},
})
.then(() => {
// The snap has been installed proceed accordingly.
})
.catch(() => {
// The snap has not been installed (user rejected the installation)
});
```


### Snap is not properly approved.

Guide users through the process of approving the Snap in MetaMask. If they deny the connection, provide a retry option.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again this is handled automatically be get-starknet. When using the invokeSnaps what we describe in the previous section should already answer this.

Specifically

provider
  .request({
    method: 'wallet_requestSnaps',
    params: {
      [snapId]: { version: snapVersion },
    },
  })
  .then(() => {
    // The snap has been installed proceed accordingly.
  })
  .catch(() => {
    // The snap has not been installed (user rejected the installation) 
    // Here we can provide retry options 
  });


# Send Starknet transactions

After the account is connected, you can send a transaction using the `starknet.invoke()` function:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The connect-to-starknet section shows how to get access to the wallet object that we use here

Suggested change
After the account is connected, you can send a transaction using the `starknet.invoke()` function:
After the account is connected, you can send a transaction using the `wallet.account.execute` function:

Copy link
Contributor

@alexandratran alexandratran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added more comments. Some are high-level – I will return to certain pages when they're more copy-edit ready.

wallet/how-to/use-non-evm-networks/_category_.json Outdated Show resolved Hide resolved
wallet/how-to/use-non-evm-networks/index.md Outdated Show resolved Hide resolved

Starknet is a non-EVM Layer 2 network. To interact with Starknet accounts in MetaMask, you need to use the Starknet Snap.

You can use the `get-starknet` library or the `wallet_invokeSnap` JSON-RPC method to connect to the Starknet Snap.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add links to get-starknet library and wallet_invokeSnap docs.

wallet/how-to/use-non-evm-networks/starknet/index.md Outdated Show resolved Hide resolved
wallet/how-to/use-non-evm-networks/starknet/index.md Outdated Show resolved Hide resolved
sidebar_position: 6
---

# Build a Basic dApp with get-starknet and React TypeScript
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Build a Basic dApp with get-starknet and React TypeScript
# Create a simple Starknet dapp

Simplify title for cleaner sidebar.


# Build a Basic dApp with get-starknet and React TypeScript

In this tutorial, you'll learn how to set up a basic dApp that uses get-starknet to connect to MetaMask and display the user's wallet address.
Copy link
Contributor

@alexandratran alexandratran Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In this tutorial, you'll learn how to set up a basic dApp that uses get-starknet to connect to MetaMask and display the user's wallet address.
In this tutorial, you'll learn how to set up a basic dapp that uses the `get-starknet` library to connect to MetaMask and display the user's wallet address.

# Build a Basic dApp with get-starknet and React TypeScript

In this tutorial, you'll learn how to set up a basic dApp that uses get-starknet to connect to MetaMask and display the user's wallet address.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add prerequisites? yarn, text editor, etc.


In this tutorial, you'll learn how to set up a basic dApp that uses get-starknet to connect to MetaMask and display the user's wallet address.

## 1. Project Setup
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## 1. Project Setup
## 1. Set up the project

It looks like this tutorial might be copy-paste and needs an editing pass? I'll refrain from adding more comments until it's more ready. Headings should be sentence case and avoid gerunds. Admonitions should be properly formatted, etc.

<!--For the dapp, the primary action to initiate interacting with Starknet accounts is to connect to the Snap, just like a dapp connects with MetaMask to interact with Ethereum accounts. Whether the user has the Starknet Snap installed already is not important. If the user needs to install the Snap, they will be prompted to do so.
Despite this, we do need to explain that the user can reject the prompt to add the Snap to MetaMask and document what to expect (the response that the dapp will receive if the user rejects the request) and encourage the dapp to do something in that instance, like display a message to the user that they need to add the Snap to MetaMask in order to proceed.
Also, in terms of working with Starknet specifically, we may need to explain that a user will need to take some steps to set up a Starknet account before they can actually use it with the dapp, so the dapp should thoughtfully design that onboarding flow. Whether the user needs to add the Snap (and thus they will be completely new to Starknet) or they already have it but their account is not funded or deployed, the dapp should handle those scenarios.-->

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add brief intro to this page, and remove ordered lists from the headings.

@joaniefromtheblock
Copy link
Contributor Author

Added more comments. Some are high-level – I will return to certain pages when they're more copy-edit ready.

Okay sorry, I still didn't push changes for the tutorial and troubleshoot section. Sorry, thought I mentioned in our sync

@joaniefromtheblock
Copy link
Contributor Author

@alexandratran pushed changes and suggestions, but am still working on tutorial and troubleshoot section. I ran into some issues/ errors when trying to replicate the steps for the tutorial.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants