diff --git a/snaps/features/custom-evm-accounts/create-account-snap.md b/snaps/features/custom-evm-accounts/create-account-snap.md index b1822840145..2c61040f3bf 100644 --- a/snaps/features/custom-evm-accounts/create-account-snap.md +++ b/snaps/features/custom-evm-accounts/create-account-snap.md @@ -48,16 +48,16 @@ Specify the following [permissions](../../how-to/request-permissions.md) in your ```json title="snap.manifest.json" "initialPermissions": { - "endowment:keyring": { - "allowedOrigins": [ - "https://" - ] - }, - "endowment:rpc": { - "dapps": true - }, - "snap_manageAccounts": {}, - "snap_manageState": {} + "endowment:keyring": { + "allowedOrigins": [ + "https://" + ] + }, + "endowment:rpc": { + "dapps": true + }, + "snap_manageAccounts": {}, + "snap_manageState": {} }, ``` @@ -71,7 +71,7 @@ Make sure to [limit the methods exposed to dapps](security.md#limit-the-methods- ```typescript class MySnapKeyring implements Keyring { - // Implement the required methods here. + // Implement the required methods here. } ``` @@ -87,16 +87,16 @@ The following is an example of a `personal_sign` request: ```json { - "id": "d6e23af6-4bea-48dd-aeb0-7d3c30ea67f9", - "scope": "", - "account": "69438371-bef3-4957-9f91-c3f22c1d75f3", - "request": { - "method": "personal_sign", - "params": [ - "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", - "0x5874174dcf1ab6F7Efd8496f4f09404CD1c5bA84" - ] - } + "id": "d6e23af6-4bea-48dd-aeb0-7d3c30ea67f9", + "scope": "", + "account": "69438371-bef3-4957-9f91-c3f22c1d75f3", + "request": { + "method": "personal_sign", + "params": [ + "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", + "0x5874174dcf1ab6F7Efd8496f4f09404CD1c5bA84" + ] + } } ``` @@ -139,10 +139,10 @@ For example, when an account is created: ```typescript try { - emitSnapKeyringEvent(snap, KeyringEvent.AccountCreated, { account }); - // Update your Snap's state. + emitSnapKeyringEvent(snap, KeyringEvent.AccountCreated, { account }); + // Update your Snap's state. } catch (error) { - // Handle the error. + // Handle the error. } ``` @@ -155,11 +155,11 @@ to MetaMask and your dapp: ```typescript export const onKeyringRequest: OnKeyringRequestHandler = async ({ - origin, - request, + origin, + request, }) => { - // Add custom logic here. - return handleKeyringRequest(keyring, request); + // Add custom logic here. + return handleKeyringRequest(keyring, request); }; ``` diff --git a/snaps/features/custom-evm-accounts/security.md b/snaps/features/custom-evm-accounts/security.md index 96c0769f2f3..2243a9dd273 100644 --- a/snaps/features/custom-evm-accounts/security.md +++ b/snaps/features/custom-evm-accounts/security.md @@ -28,20 +28,20 @@ For example: ```ts const account: KeyringAccount = { - id: uuid(), - options: { - privateKey: "0x01234...78", // !!! DO NOT DO THIS !!! - }, - address, - methods: [ - EthMethod.PersonalSign, - EthMethod.Sign, - EthMethod.SignTransaction, - EthMethod.SignTypedDataV1, - EthMethod.SignTypedDataV3, - EthMethod.SignTypedDataV4, - ], - type: EthAccountType.Eoa, + id: uuid(), + options: { + privateKey: "0x01234...78", // !!! DO NOT DO THIS !!! + }, + address, + methods: [ + EthMethod.PersonalSign, + EthMethod.Sign, + EthMethod.SignTransaction, + EthMethod.SignTypedDataV1, + EthMethod.SignTypedDataV3, + EthMethod.SignTypedDataV4, + ], + type: EthAccountType.Eoa, }; ``` @@ -51,14 +51,14 @@ For example: ```ts await snap.request({ - method: "snap_manageState", - params: { - operation: "update", - newState: { - // Your Snap's state here. - privateKey: "0x01234...78", - }, + method: "snap_manageState", + params: { + operation: "update", + newState: { + // Your Snap's state here. + privateKey: "0x01234...78", }, + }, }); ``` @@ -101,16 +101,16 @@ The following is an example of implementing such logic: ```ts const permissions: Record = { - "https://": [ - // List of allowed methods for Dapp 1. - ], - "https://": [ - // List of allowed methods for Dapp 2. - ], + "https://": [ + // List of allowed methods for Dapp 1. + ], + "https://": [ + // List of allowed methods for Dapp 2. + ], }; if (origin !== "metamask" && !permissions[origin]?.includes(request.method)) { - // Reject the request. + // Reject the request. } ``` @@ -124,14 +124,14 @@ redirected to a malicious website. ```ts async submitRequest(request: KeyringRequest): Promise { - // Your Snap's custom logic. - return { - pending: true, - redirect: { - message: "Please continue in the dapp.", - url: "https:///sign?tx=1234", // !!! ENSURE THIS IS A SAFE URL !!! - }, - }; + // Your Snap's custom logic. + return { + pending: true, + redirect: { + message: "Please continue in the dapp.", + url: "https:///sign?tx=1234", // !!! ENSURE THIS IS A SAFE URL !!! + }, + }; } ``` @@ -170,10 +170,10 @@ For example: ```ts try { - const privateKey = toBuffer(inputSecretValue); - // Use privateKey here. + const privateKey = toBuffer(inputSecretValue); + // Use privateKey here. } catch (error) { - throw new Error("Invalid private key"); + throw new Error("Invalid private key"); } ``` @@ -190,11 +190,11 @@ For example: ```ts export const onRpcRequest: OnRpcRequestHandler = async ({ - // ~~~ ~~~ - origin, - request, + // ~~~ ~~~ + origin, + request, }) => { - return handleKeyringRequest(keyring, request); + return handleKeyringRequest(keyring, request); }; ``` @@ -202,12 +202,12 @@ For example: ```ts export const onKeyringRequest: OnKeyringRequestHandler = async ({ - // ~~~~~~~ ~~~~~~~ - origin, - request, + // ~~~~~~~ ~~~~~~~ + origin, + request, }) => { - // Any custom logic or extra security checks here. - return handleKeyringRequest(keyring, request); + // Any custom logic or extra security checks here. + return handleKeyringRequest(keyring, request); }; ``` diff --git a/snaps/features/custom-name-resolution.md b/snaps/features/custom-name-resolution.md index 66750898cb1..805b4c5374e 100644 --- a/snaps/features/custom-name-resolution.md +++ b/snaps/features/custom-name-resolution.md @@ -22,9 +22,9 @@ For example, to resolve Ethereum Mainnet domains, add the following to your Snap ```json title="snap.manifest.json" "initialPermissions": { - "endowment:name-lookup": { - "chains": ["eip155:1"] - } + "endowment:name-lookup": { + "chains": ["eip155:1"] + } } ``` @@ -41,25 +41,25 @@ import type { OnNameLookupHandler } from "@metamask/snaps-types"; const UNSTOPPABLE_API_KEY = "xxx"; export const onNameLookup: OnNameLookupHandler = async (request) => { - const { chainId, domain } = request; - - if (domain && chainId === "eip155:1") { - const response = await fetch(`https://api.unstoppabledomains.com/resolve/domains/${domain}`, { - headers: { - accept: "application/json", - authorization: `Bearer ${UNSTOPPABLE_API_KEY}`, - }, - }); - const data = await response.json(); - const resolvedAddress = data.records["crypto.ETH.address"]; - if (address) { - return { - resolvedAddresses: [{ resolvedAddress, protocol: "Unstoppable Domains" }], - }; - } + const { chainId, domain } = request; + + if (domain && chainId === "eip155:1") { + const response = await fetch(`https://api.unstoppabledomains.com/resolve/domains/${domain}`, { + headers: { + accept: "application/json", + authorization: `Bearer ${UNSTOPPABLE_API_KEY}`, + }, + }); + const data = await response.json(); + const resolvedAddress = data.records["crypto.ETH.address"]; + if (address) { + return { + resolvedAddresses: [{ resolvedAddress, protocol: "Unstoppable Domains" }], + }; } + } - return null; + return null; }; ``` diff --git a/snaps/features/custom-ui/index.md b/snaps/features/custom-ui/index.md index eec21868856..cf5f16f2a84 100644 --- a/snaps/features/custom-ui/index.md +++ b/snaps/features/custom-ui/index.md @@ -28,14 +28,14 @@ For example, to display a [`panel`](#panel) using [`snap_dialog`](../../referenc import { panel, heading, text } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Alert heading"), - text("Something happened in the system."), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Alert heading"), + text("Something happened in the system."), + ]), + }, }); ``` @@ -55,14 +55,14 @@ Hovering the address shows the full value in a tooltip. import { panel, heading, address } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Are you sure you want to send tokens to this address?"), - address("0x000000000000000000000000000000000000dEaD"), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Are you sure you want to send tokens to this address?"), + address("0x000000000000000000000000000000000000dEaD"), + ]), + }, }); ``` @@ -102,24 +102,24 @@ An object containing: import { button, panel, heading } from "@metamask/snaps-sdk"; const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: panel([ - heading("Interactive interface"), - button({ - value: "Click me", - name: "interactive-button", - }), - ]), - }, + method: "snap_createInterface", + params: { + ui: panel([ + heading("Interactive interface"), + button({ + value: "Click me", + name: "interactive-button", + }), + ]), + }, }); await snap.request({ - method: "snap_dialog", - params: { - type: "Alert", - id: interfaceId, - }, + method: "snap_dialog", + params: { + type: "Alert", + id: interfaceId, + }, }); ``` @@ -137,14 +137,14 @@ Outputs a read-only text field with a copy-to-clipboard shortcut. import { text, copyable } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - text("Your address:"), - copyable("0x000000000000000000000000000000000000dEaD"), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + text("Your address:"), + copyable("0x000000000000000000000000000000000000dEaD"), + ]), + }, }); ``` @@ -163,13 +163,13 @@ import type { OnHomePageHandler } from "@metamask/snaps-sdk"; import { panel, divider, text } from "@metamask/snaps-sdk"; module.exports.onHomePage = async () => { - return { - content: panel([ - heading("Hello world!"), - divider(), - text("Welcome to my Snap home page!"), - ]), - }; + return { + content: panel([ + heading("Hello world!"), + divider(), + text("Welcome to my Snap home page!"), + ]), + }; }; ``` @@ -198,30 +198,30 @@ An object containing: import { input, button, form } from "@metamask/snaps-sdk"; const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: form({ - name: "form-to-fill", - children: [ - input({ - name: "user-name", - placeholder: "Your name", - }), - button({ - value: "Submit", - buttonType: "submit", - }), - ], + method: "snap_createInterface", + params: { + ui: form({ + name: "form-to-fill", + children: [ + input({ + name: "user-name", + placeholder: "Your name", }), - }, + button({ + value: "Submit", + buttonType: "submit", + }), + ], + }), + }, }); await snap.request({ - method: "snap_dialog", - params: { - type: "Alert", - id: interfaceId, - }, + method: "snap_dialog", + params: { + type: "Alert", + id: interfaceId, + }, }); ``` @@ -241,12 +241,12 @@ import type { OnHomePageHandler } from "@metamask/snaps-sdk"; import { panel, heading, text } from "@metamask/snaps-sdk"; module.exports.onHomePage = async () => { - return { - content: panel([ - heading("Hello world!"), - text("Welcome to my Snap home page!"), - ]), - }; + return { + content: panel([ + heading("Hello world!"), + text("Welcome to my Snap home page!"), + ]), + }; }; ``` @@ -280,13 +280,13 @@ import { panel, heading, text, image } from "@metamask/snaps-sdk"; import svgIcon from "./path/to/icon.svg"; module.exports.onHomePage = async () => { - return { - content: panel([ - heading("Hello world!"), - text("Welcome to my Snap home page!"), - image(svgIcon), - ]), - }; + return { + content: panel([ + heading("Hello world!"), + text("Welcome to my Snap home page!"), + image(svgIcon), + ]), + }; }; ``` @@ -320,30 +320,30 @@ An object containing: import { input, form } from "@metamask/snaps-sdk"; const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: form({ - name: "form-to-fill", - children: [ - input({ - name: "user-name", - placeholder: "Your name", - }), - button({ - value: "Submit", - buttonType: "submit", - }), - ], + method: "snap_createInterface", + params: { + ui: form({ + name: "form-to-fill", + children: [ + input({ + name: "user-name", + placeholder: "Your name", + }), + button({ + value: "Submit", + buttonType: "submit", }), - }, + ], + }), + }, }); await snap.request({ - method: "snap_dialog", - params: { - type: "Alert", - id: interfaceId, - }, + method: "snap_dialog", + params: { + type: "Alert", + id: interfaceId, + }, }); ``` @@ -368,17 +368,17 @@ import type { OnTransactionHandler } from "@metamask/snaps-sdk"; import { panel, heading, text } from "@metamask/snaps-sdk"; module.exports.onTransaction = async ({ transaction }) => { - const gasFeesPercentage = /* Calculate gas fees percentage */; - return { - content: panel([ - heading("Transaction insights"), - text( - `As set up, you are paying **${gasFeesPercentage.toFixed( - 2, - )}%** in gas fees for this transaction.`, - ), - ]), - }; + const gasFeesPercentage = /* Calculate gas fees percentage */; + return { + content: panel([ + heading("Transaction insights"), + text( + `As set up, you are paying **${gasFeesPercentage.toFixed( + 2, + )}%** in gas fees for this transaction.`, + ), + ]), + }; }; ``` @@ -398,14 +398,14 @@ The label must be a string. The value can be a child component of type import { panel, row, text, address } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - row("Address", address("0x000000000000000000000000000000000000dEaD")), - row("Balance", text("1.78 ETH")), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + row("Address", address("0x000000000000000000000000000000000000dEaD")), + row("Balance", text("1.78 ETH")), + ]), + }, }); ``` @@ -423,14 +423,14 @@ Outputs a loading indicator. import { panel, heading, spinner } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Please wait..."), - spinner(), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Please wait..."), + spinner(), + ]), + }, }); ``` @@ -449,12 +449,12 @@ import type { OnHomePageHandler } from "@metamask/snaps-sdk"; import { panel, heading, text } from "@metamask/snaps-sdk"; module.exports.onHomePage = async () => { - return { - content: panel([ - heading("Hello world!"), - text("Welcome to my Snap home page!"), - ]), - }; + return { + content: panel([ + heading("Hello world!"), + text("Welcome to my Snap home page!"), + ]), + }; }; ``` @@ -472,14 +472,14 @@ module.exports.onHomePage = async () => { import { panel, heading, text } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Hello world!"), - text("This is **bold** and this is _italic_."), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Hello world!"), + text("This is **bold** and this is _italic_."), + ]), + }, }); ``` @@ -498,13 +498,13 @@ import type { OnHomePageHandler } from "@metamask/snaps-sdk"; import { panel, text } from "@metamask/snaps-sdk"; module.exports.onHomePage = async () => { - return { - content: panel([ - heading("Hello world!"), - text("Download [MetaMask](https://metamask.io)."), - text("Read the MetaMask docs at [](https://docs.metamask.io)."), - ]), - }; + return { + content: panel([ + heading("Hello world!"), + text("Download [MetaMask](https://metamask.io)."), + text("Read the MetaMask docs at [](https://docs.metamask.io)."), + ]), + }; }; ``` @@ -522,14 +522,14 @@ Text-based components (such as [`heading`](#heading) and [`text`](#text)) accept import { panel, heading, text } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Hello world!"), - text("This is an apple 🍎 and this is an orange 🍊."), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Hello world!"), + text("This is an apple 🍎 and this is an orange 🍊."), + ]), + }, }); ``` diff --git a/snaps/features/localization.md b/snaps/features/localization.md index f5b501134b9..64943aa2308 100644 --- a/snaps/features/localization.md +++ b/snaps/features/localization.md @@ -18,10 +18,8 @@ To call `snap_getLocale`, first request the required permission by adding it to `initialPermissions` field in your manifest file: ```json title="snap.manifest.json" -{ - "initialPermissions": { - "snap_getLocale": {} - } +"initialPermissions": { + "snap_getLocale": {} } ``` @@ -36,13 +34,13 @@ following format: ```json title="en.json" { - "locale": "en", - "messages": { - "hello": { - "message": "Hello, world!", - "description": "The message that is returned when the `hello` method is called." - } + "locale": "en", + "messages": { + "hello": { + "message": "Hello, world!", + "description": "The message that is returned when the `hello` method is called." } + } } ``` @@ -59,18 +57,18 @@ import nl from "../locales/nl.json"; const FALLBACK_LANGUAGE: Locale = "en"; export const locales = { - da: da.messages, - en: en.messages, - nl: nl.messages, + da: da.messages, + en: en.messages, + nl: nl.messages, }; export type Locale = keyof typeof locales; export async function getMessage(id: keyof (typeof locales)[Locale]) { - const locale = (await snap.request({ method: "snap_getLocale" })) as Locale; - const { message } = locales[locale]?.[id] ?? locales[FALLBACK_LANGUAGE][id]; + const locale = (await snap.request({ method: "snap_getLocale" })) as Locale; + const { message } = locales[locale]?.[id] ?? locales[FALLBACK_LANGUAGE][id]; - return message; + return message; } ``` @@ -86,15 +84,15 @@ import type { OnRpcRequestHandler } from "@metamask/snaps-sdk"; import { getMessage } from "./locales"; export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => { - switch (request.method) { - case "hello": - return await getMessage("hello"); - - default: - throw rpcErrors.methodNotFound({ - data: { method: request.method }, - }); - } + switch (request.method) { + case "hello": + return await getMessage("hello"); + + default: + throw rpcErrors.methodNotFound({ + data: { method: request.method }, + }); + } }; ``` @@ -107,21 +105,21 @@ The following is an example of a localized manifest file: ```json title="snap.manifest.json" { - "version": "1.1.1", - "description": "{{ description }}", - "proposedName": "{{ name }}", - "source": { - "shasum": "XXX", - "locales": [ - "locales/da.json", - "locales/en.json", - "locales/nl.json" - ] - }, - "initialPermissions": { - "snap_getLocale": {} - }, - "manifestVersion": "0.1" + "version": "1.1.1", + "description": "{{ description }}", + "proposedName": "{{ name }}", + "source": { + "shasum": "XXX", + "locales": [ + "locales/da.json", + "locales/en.json", + "locales/nl.json" + ] + }, + "initialPermissions": { + "snap_getLocale": {} + }, + "manifestVersion": "0.1" } ``` diff --git a/snaps/features/non-evm-networks.md b/snaps/features/non-evm-networks.md index be5e4c3f3bc..3986a33aabf 100644 --- a/snaps/features/non-evm-networks.md +++ b/snaps/features/non-evm-networks.md @@ -64,14 +64,12 @@ For example, to derive Dogecoin keys: 2. Dogecoin has coin type `3`, so add the following to the manifest file: ```json title="snap.manifest.json" - { - "initialPermissions": { - "snap_getBip44Entropy": [ - { - "coinType": 3 - } - ] + "initialPermissions": { + "snap_getBip44Entropy": [ + { + "coinType": 3 } + ] } ``` @@ -88,10 +86,10 @@ For example, to derive Dogecoin keys: // Get the Dogecoin node, corresponding to the path m/44'/3'. const dogecoinNode = await snap.request({ - method: "snap_getBip44Entropy", - params: { - coinType: 3, - }, + method: "snap_getBip44Entropy", + params: { + coinType: 3, + }, }); /** diff --git a/snaps/features/signature-insights.md b/snaps/features/signature-insights.md index f64875a2818..f0717e14be2 100644 --- a/snaps/features/signature-insights.md +++ b/snaps/features/signature-insights.md @@ -24,10 +24,8 @@ Request the [`endowment:signature-insight`](../reference/permissions.md#endowmen permission by adding the following to your Snap's manifest file: ```json title="snap.manifest.json" -{ - "initialPermissions": { - "endowment:signature-insight": {} - } +"initialPermissions": { + "endowment:signature-insight": {} } ``` @@ -35,12 +33,10 @@ If you need to receive the origin of the signature request, add `allowSignatureO permission object, and set it to `true`: ```json title="snap.manifest.json" -{ - "initialPermissions": { - "endowment:signature-insight": { - "allowSignatureOrigin": true - } - } +"initialPermissions": { + "endowment:signature-insight": { + "allowSignatureOrigin": true + } } ``` @@ -65,9 +61,9 @@ shapes, depending on the signing method used: ```typescript interface EthSignature { - from: string; - data: string; - signatureMethod: "eth_sign"; + from: string; + data: string; + signatureMethod: "eth_sign"; } ``` @@ -76,9 +72,9 @@ interface EthSignature { ```typescript interface PersonalSignature { - from: string; - data: string; - signatureMethod: "personal_sign"; + from: string; + data: string; + signatureMethod: "personal_sign"; } ``` @@ -87,9 +83,9 @@ interface PersonalSignature { ```typescript interface SignTypedDataSignature { - from: string; - data: Record[]; - signatureMethod: "eth_signTypedData"; + from: string; + data: Record[]; + signatureMethod: "eth_signTypedData"; } ``` @@ -98,9 +94,9 @@ interface SignTypedDataSignature { ```typescript interface SignTypedDataV3Signature { - from: string; - data: Record; - signatureMethod: "eth_signTypedData_v3"; + from: string; + data: Record; + signatureMethod: "eth_signTypedData_v3"; } ``` @@ -109,9 +105,9 @@ interface SignTypedDataV3Signature { ```typescript interface SignTypedDataV4Signature { - from: string; - data: Record; - signatureMethod: "eth_signTypedData_v4"; + from: string; + data: Record; + signatureMethod: "eth_signTypedData_v4"; } ``` @@ -139,18 +135,18 @@ import type { OnSignatureHandler, SeverityLevel } from "@metamask/snaps-sdk"; import { panel, heading, text } from "@metamask/snaps-sdk"; export const onSignature: OnSignatureHandler = async ({ - signature, - signatureOrigin, + signature, + signatureOrigin, }) => { - const insights = /* Get insights based on custom logic */; - return { - content: panel([ - heading("My Signature Insights"), - text("Here are the insights:"), - ...(insights.map((insight) => text(insight.value))), - ]), - severity: SeverityLevel.Critical, - }; + const insights = /* Get insights based on custom logic */; + return { + content: panel([ + heading("My Signature Insights"), + text("Here are the insights:"), + ...(insights.map((insight) => text(insight.value))), + ]), + severity: SeverityLevel.Critical, + }; }; ``` diff --git a/snaps/features/static-files.md b/snaps/features/static-files.md index 35caf057ea8..aaf7bf7c8f2 100644 --- a/snaps/features/static-files.md +++ b/snaps/features/static-files.md @@ -19,16 +19,14 @@ File paths are relative to the Snap package root, that is, one level above the ` For example: ```json title="snap.manifest.json" -{ - "source": { - "shasum": "xxx", - "location": { - // ... - }, - "files": [ - "./files/myfile.bin" - ] - } +"source": { + "shasum": "xxx", + "location": { + // ... + }, + "files": [ + "./files/myfile.bin" + ] } ``` @@ -40,11 +38,11 @@ For example: ```javascript title="index.js" const contents = await snap.request({ - method: "snap_getFile", - params: { - path: "./files/myfile.bin", - encoding: "hex", - }, + method: "snap_getFile", + params: { + path: "./files/myfile.bin", + encoding: "hex", + }, }); // "0x..." diff --git a/snaps/get-started/quickstart.md b/snaps/get-started/quickstart.md index 9c692c82015..a2926f096d0 100644 --- a/snaps/get-started/quickstart.md +++ b/snaps/get-started/quickstart.md @@ -103,27 +103,27 @@ import { panel, text } from "@metamask/snaps-sdk"; * @throws If the request method is not valid for this Snap. */ export const onRpcRequest: OnRpcRequestHandler = async ({ - origin, - request, + origin, + request, }) => { - switch (request.method) { - case "hello": - return snap.request({ - method: "snap_dialog", - params: { - type: "confirmation", - content: panel([ - text(`Hello, **${origin}**!`), - text("This custom confirmation is just for display purposes."), - text( - "But you can edit the Snap source code to make it do something, if you want to!", - ), - ]), - }, - }); - default: - throw new Error("Method not found."); - } + switch (request.method) { + case "hello": + return snap.request({ + method: "snap_dialog", + params: { + type: "confirmation", + content: panel([ + text(`Hello, **${origin}**!`), + text("This custom confirmation is just for display purposes."), + text( + "But you can edit the Snap source code to make it do something, if you want to!", + ), + ]), + }, + }); + default: + throw new Error("Method not found."); + } }; ``` diff --git a/snaps/how-to/communicate-errors.md b/snaps/how-to/communicate-errors.md index 2e73e71b123..1f466e502a5 100644 --- a/snaps/how-to/communicate-errors.md +++ b/snaps/how-to/communicate-errors.md @@ -21,13 +21,13 @@ import type { OnRpcRequestHandler } from "@metamask/snaps-sdk"; import { MethodNotFoundError } from "@metamask/snaps-sdk"; export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => { - switch (request.method) { - case "hello": - return "Hello World!"; - default: - // Throw a known error to avoid crashing the Snap. - throw new MethodNotFoundError(); - } + switch (request.method) { + case "hello": + return "Hello World!"; + default: + // Throw a known error to avoid crashing the Snap. + throw new MethodNotFoundError(); + } }; ``` @@ -37,7 +37,7 @@ The error class constructors exported by `@metamask/snaps-sdk` have the followin ```typescript class SnapJsonRpcError extends SnapError { - new (message?: string, data?: Record) + new (message?: string, data?: Record) } ``` diff --git a/snaps/how-to/connect-to-a-snap.md b/snaps/how-to/connect-to-a-snap.md index f40719fd6f8..ac496de1f24 100644 --- a/snaps/how-to/connect-to-a-snap.md +++ b/snaps/how-to/connect-to-a-snap.md @@ -31,14 +31,14 @@ const provider = await detectEthereumProvider(); // web3_clientVersion returns the installed MetaMask version as a string. const isFlask = ( - await provider?.request({ method: "web3_clientVersion" }) + await provider?.request({ method: "web3_clientVersion" }) )?.includes("flask"); if (provider && isFlask) { - console.log("MetaMask Flask successfully detected!"); - // Now you can use Snaps! + console.log("MetaMask Flask successfully detected!"); + // Now you can use Snaps! } else { - console.error("Please install MetaMask Flask!", error); + console.error("Please install MetaMask Flask!", error); } ``` @@ -74,15 +74,15 @@ with the following shape: ```json { - "SNAP_ID": { - "blocked": false, - "enabled": true, - "id": "SNAP_ID", - "initialPermissions": { - // ...all the permissions in the Snap's manifest - }, - "version": "SNAP_VERSION" - } + "SNAP_ID": { + "blocked": false, + "enabled": true, + "id": "SNAP_ID", + "initialPermissions": { + // The permissions in the Snap's manifest file. + }, + "version": "SNAP_VERSION" + } } ``` @@ -144,14 +144,14 @@ However, if the user has disabled the Snap, the response has `enabled` set to `f ```json { - "SNAP_ID": { - "blocked": false, - "enabled": false, - "id": "SNAP_ID", - "initialPermissions": { - // ...all the permissions in the Snap's manifest - }, - "version": "SNAP_VERSION" - } + "SNAP_ID": { + "blocked": false, + "enabled": false, + "id": "SNAP_ID", + "initialPermissions": { + // The permissions in the Snap's manifest file. + }, + "version": "SNAP_VERSION" + } } ``` diff --git a/snaps/how-to/debug-a-snap/common-issues.md b/snaps/how-to/debug-a-snap/common-issues.md index 329fad76b82..327de583a81 100644 --- a/snaps/how-to/debug-a-snap/common-issues.md +++ b/snaps/how-to/debug-a-snap/common-issues.md @@ -87,7 +87,7 @@ Then add a postinstall script to your `package.json`: ```diff title="package.json" "scripts": { -+ "postinstall": "patch-package" ++ "postinstall": "patch-package" } ``` @@ -127,8 +127,8 @@ You can replace that with the following snippet: ```javascript title="browser-ponyfill.js" // Choose between native implementation (global) or custom implementation (__self__) var ctx = global.fetch - ? { ...global, fetch: global.fetch.bind(global) } - : __self__; + ? { ...global, fetch: global.fetch.bind(global) } + : __self__; // var ctx = __self__; // this line disable service worker support temporarily ``` @@ -177,23 +177,23 @@ In a production environment this may be a large task depending on the usage of ` ```javascript const instance = axios.create({ - baseURL: "https://api.github.com/", + baseURL: "https://api.github.com/", }); instance - .get("users/MetaMask") - .then((res) => { - if (res.status >= 400) { - throw new Error("Bad response from server"); - } - return res.data; - }) - .then((user) => { - console.log(user); - }) - .catch((err) => { - console.error(err); - }); + .get("users/MetaMask") + .then((res) => { + if (res.status >= 400) { + throw new Error("Bad response from server"); + } + return res.data; + }) + .then((user) => { + console.log(user); + }) + .catch((err) => { + console.error(err); + }); ``` @@ -201,14 +201,14 @@ instance ```javascript fetch("https://api.github.com/users/MetaMask") - .then((res) => { - if (!res.ok) { - throw new Error("Bad response from server"); - } - return res.json(); - }) - .then((json) => console.log(json)) - .catch((err) => console.error(err)); + .then((res) => { + if (!res.ok) { + throw new Error("Bad response from server"); + } + return res.json(); + }) + .then((json) => console.log(json)) + .catch((err) => console.error(err)); ``` diff --git a/snaps/how-to/request-permissions.md b/snaps/how-to/request-permissions.md index ee41098b85f..abb25345fdd 100644 --- a/snaps/how-to/request-permissions.md +++ b/snaps/how-to/request-permissions.md @@ -23,7 +23,7 @@ following to the manifest file: ```json title="snap.manifest.json" "initialPermissions": { - "snap_dialog": {} + "snap_dialog": {} } ``` @@ -48,7 +48,7 @@ permission, add the following to the manifest file: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:network-access": {} + "endowment:network-access": {} } ``` @@ -71,17 +71,17 @@ The following example calls `wallet_requestSnaps` to request permission to conne ```js title="index.js" // If the Snap is not already installed, the user will be prompted to install it. await window.ethereum.request({ - method: "wallet_requestSnaps", - params: { - // Assuming the Snap is published to npm using the package name "hello-snap". - "npm:hello-snap": {}, - }, + method: "wallet_requestSnaps", + params: { + // Assuming the Snap is published to npm using the package name "hello-snap". + "npm:hello-snap": {}, + }, }); // Invoke the "hello" JSON-RPC method exposed by the Snap. const response = await window.ethereum.request({ - method: "wallet_invokeSnap", - params: { snapId: "npm:hello-snap", request: { method: "hello" } }, + method: "wallet_invokeSnap", + params: { snapId: "npm:hello-snap", request: { method: "hello" } }, }); console.log(response); // "world!" diff --git a/snaps/how-to/restrict-rpc-api.md b/snaps/how-to/restrict-rpc-api.md index ed215e83e8e..a484f0f8f12 100644 --- a/snaps/how-to/restrict-rpc-api.md +++ b/snaps/how-to/restrict-rpc-api.md @@ -31,36 +31,36 @@ import type { OnRpcRequestHandler, UnauthorizedError } from "@metamask/snaps-sdk type MethodPermission = "*" | string[]; const RPC_PERMISSIONS: Record = { - hello: "*", - secureMethod: [ - "https://metamask.io", - "https://www.mydomain.com", - ] + hello: "*", + secureMethod: [ + "https://metamask.io", + "https://www.mydomain.com", + ] }; const isAllowed = (method: string, origin: string) => { - return RPC_PERMISSIONS[method] === "*" || RPC_PERMISSIONS[method].includes(origin); + return RPC_PERMISSIONS[method] === "*" || RPC_PERMISSIONS[method].includes(origin); }; export const onRpcRequest: OnRpcRequestHandler = async ({ - origin, - request, + origin, + request, }) => { - // Check permissions - if (!isAllowed(request.method, origin)) { - throw new UnauthorizedError(`Method ${request.method} not authorized for origin ${origin}.`); - } - - switch (request.method) { - case "hello": - return "world!"; - - case "secureMethod": - return "The secret is: 42"; - - default: - throw new Error("Method not found."); - } + // Check permissions. + if (!isAllowed(request.method, origin)) { + throw new UnauthorizedError(`Method ${request.method} not authorized for origin ${origin}.`); + } + + switch (request.method) { + case "hello": + return "world!"; + + case "secureMethod": + return "The secret is: 42"; + + default: + throw new Error("Method not found."); + } }; ``` diff --git a/snaps/how-to/test-a-snap.md b/snaps/how-to/test-a-snap.md index 84a97914730..ca687d6483f 100644 --- a/snaps/how-to/test-a-snap.md +++ b/snaps/how-to/test-a-snap.md @@ -36,7 +36,7 @@ In the `jest.config.js` file, add the following: ```js title="jest.config.js" module.exports = { - preset: "@metamask/snaps-jest", + preset: "@metamask/snaps-jest", }; ``` @@ -56,8 +56,8 @@ environment and matchers to your Jest configuration manually: ```js title="jest.config.js" module.exports = { - testEnvironment: "@metamask/snaps-jest", - setupFilesAfterEnv: ["@metamask/snaps-jest/dist/cjs/setup.js"], + testEnvironment: "@metamask/snaps-jest", + setupFilesAfterEnv: ["@metamask/snaps-jest/dist/cjs/setup.js"], }; ``` @@ -67,10 +67,10 @@ For example: ```js title="jest.config.js" module.exports = { - preset: "@metamask/snaps-jest", - testEnvironmentOptions: { - // Options go here. - }, + preset: "@metamask/snaps-jest", + testEnvironmentOptions: { + // Options go here. + }, }; ``` diff --git a/snaps/how-to/use-environment-variables.md b/snaps/how-to/use-environment-variables.md index 4393002b617..3edb71e61be 100644 --- a/snaps/how-to/use-environment-variables.md +++ b/snaps/how-to/use-environment-variables.md @@ -58,11 +58,11 @@ Snaps CLI: require("dotenv").config(); module.exports = { - environment: { - SNAP_ENV: process.env.SNAP_ENV, - PUBLIC_KEY: process.env.PUBLIC_KEY, - }, - // Other options. + environment: { + SNAP_ENV: process.env.SNAP_ENV, + PUBLIC_KEY: process.env.PUBLIC_KEY, + }, + // Other options. }; ``` @@ -75,11 +75,11 @@ Snaps CLI: dotenv.config(); const config: SnapConfig = { - environment: { - SNAP_ENV: process.env.SNAP_ENV, - PUBLIC_KEY: process.env.PUBLIC_KEY, - }, - // Other options. + environment: { + SNAP_ENV: process.env.SNAP_ENV, + PUBLIC_KEY: process.env.PUBLIC_KEY, + }, + // Other options. }; export default config; @@ -95,13 +95,13 @@ Snaps CLI: import { panel, text, heading } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("This custom alert is just for display purposes."), - text(`SNAP_ENV is ${process.env.SNAP_ENV}, PUBLIC_KEY is ${process.env.PUBLIC_KEY}`), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("This custom alert is just for display purposes."), + text(`SNAP_ENV is ${process.env.SNAP_ENV}, PUBLIC_KEY is ${process.env.PUBLIC_KEY}`), + ]), + }, }); ``` diff --git a/snaps/learn/about-snaps/apis.md b/snaps/learn/about-snaps/apis.md index 2a95e407396..728bdb5db2e 100644 --- a/snaps/learn/about-snaps/apis.md +++ b/snaps/learn/about-snaps/apis.md @@ -22,7 +22,7 @@ For example, to call [`snap_notify`](../../reference/snaps-api.md#snap_notify), ```json title="snap.manifest.json" "initialPermissions": { - "snap_notify": {} + "snap_notify": {} } ``` @@ -30,11 +30,11 @@ Your Snap can then call `snap_notify` in its source code: ```typescript title="index.ts" await snap.request({ - method: "snap_notify", - params: { - type: "inApp", - message: "Hello, world!", - }, + method: "snap_notify", + params: { + type: "inApp", + message: "Hello, world!", + }, }); ``` @@ -59,21 +59,21 @@ For example, to call `wallet_snap`: ```js title="index.js" // Request permission to connect to the Snap. await window.ethereum.request({ - method: "wallet_requestSnaps", - params: { - "npm:hello-snap": {}, - }, + method: "wallet_requestSnaps", + params: { + "npm:hello-snap": {}, + }, }); // Call the "hello" method of the Snap using wallet_snap. const response = await window.ethereum.request({ - method: "wallet_snap", - params: { - snapId: "npm:hello-snap", - request: { - method: "hello", - }, + method: "wallet_snap", + params: { + snapId: "npm:hello-snap", + request: { + method: "hello", }, + }, }); console.log(response); // "world!" @@ -91,7 +91,7 @@ the required permission: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:ethereum-provider": {} + "endowment:ethereum-provider": {} } ``` @@ -141,9 +141,9 @@ Set `dapps` to `true` to enable dapps to make JSON-RPC requests. ```json title="snap.manifest.json" "initialPermissions": { - "endowment:rpc": { - "dapps": true - } + "endowment:rpc": { + "dapps": true + } } ``` @@ -151,14 +151,14 @@ Your Snap can then implement and expose a custom API using the `onRpcRequest` fu ```typescript title="index.ts" module.exports.onRpcRequest = async ({ origin, request }) => { - switch (request.method) { - // Expose a "hello" JSON-RPC method to dapps. - case "hello": - return "world!"; - - default: - throw new Error("Method not found."); - } + switch (request.method) { + // Expose a "hello" JSON-RPC method to dapps. + case "hello": + return "world!"; + + default: + throw new Error("Method not found."); + } }; ``` @@ -168,22 +168,22 @@ A dapp can then install the Snap and call the exposed method: // Request permission to connect to the Snap. // If the Snap is not already installed, the user will be prompted to install it. await window.ethereum.request({ - method: "wallet_requestSnaps", - params: { - // Assuming the Snap is published to npm using the package name "hello-snap". - "npm:hello-snap": {}, - }, + method: "wallet_requestSnaps", + params: { + // Assuming the Snap is published to npm using the package name "hello-snap". + "npm:hello-snap": {}, + }, }); // Invoke the "hello" JSON-RPC method exposed by the Snap. const response = await window.ethereum.request({ - method: "wallet_invokeSnap", - params: { - snapId: "npm:hello-snap", - request: { - method: "hello", - }, + method: "wallet_invokeSnap", + params: { + snapId: "npm:hello-snap", + request: { + method: "hello", }, + }, }); console.log(response); // "world!" diff --git a/snaps/learn/about-snaps/files.md b/snaps/learn/about-snaps/files.md index 331df2052e5..cd090ed907d 100644 --- a/snaps/learn/about-snaps/files.md +++ b/snaps/learn/about-snaps/files.md @@ -47,26 +47,26 @@ The manifest file of `Hello World` would look something like this: ```json title="snap.manifest.json" { - "version": "1.0.0", - "proposedName": "Hello World", - "description": "A Snap that says hello!", - "repository": { - "type": "git", - "url": "https://github.com/Hello/hello-snap.git" - }, - "source": { - "shasum": "w3FltkDjKQZiPwM+AThnmypt0OFF7hj4ycg/kxxv+nU=", - "location": { - "npm": { - "filePath": "dist/bundle.js", - "iconPath": "images/icon.svg", - "packageName": "hello-snap", - "registry": "https://registry.npmjs.org/" - } - } - }, - "initialPermissions": {}, - "manifestVersion": "0.1" + "version": "1.0.0", + "proposedName": "Hello World", + "description": "A Snap that says hello!", + "repository": { + "type": "git", + "url": "https://github.com/Hello/hello-snap.git" + }, + "source": { + "shasum": "w3FltkDjKQZiPwM+AThnmypt0OFF7hj4ycg/kxxv+nU=", + "location": { + "npm": { + "filePath": "dist/bundle.js", + "iconPath": "images/icon.svg", + "packageName": "hello-snap", + "registry": "https://registry.npmjs.org/" + } + } + }, +"initialPermissions": {}, +"manifestVersion": "0.1" } ``` @@ -114,13 +114,13 @@ For example: ```javascript title="snap.config.js" module.exports = { - input: "src/index.js", - output: { - path: "dist", - }, - server: { - port: 9000, - }, + input: "src/index.js", + output: { + path: "dist", + }, + server: { + port: 9000, + }, }; ``` @@ -131,13 +131,13 @@ module.exports = { import type { SnapConfig } from "@metamask/snaps-cli"; const config: SnapConfig = { - input: "src/index.js", - output: { - path: "dist", - }, - server: { - port: 9000, - }, + input: "src/index.js", + output: { + path: "dist", + }, + server: { + port: 9000, + }, }; export default config; diff --git a/snaps/learn/best-practices/security-guidelines.md b/snaps/learn/best-practices/security-guidelines.md index b40180f6e4a..7dfc7b9365a 100644 --- a/snaps/learn/best-practices/security-guidelines.md +++ b/snaps/learn/best-practices/security-guidelines.md @@ -76,11 +76,11 @@ The following are guidelines for user notifications and authorizations: const referrer = new URL(origin); if(referrer.protocol === "https:" && - (referrer.host.endsWith(".metamask.io") || referrer.host === "metamask.io")) { - console.log("URL is valid"); + (referrer.host.endsWith(".metamask.io") || referrer.host === "metamask.io")) { + console.log("URL is valid"); } else { - console.log("URL is NOT valid"); + console.log("URL is NOT valid"); } ``` diff --git a/snaps/learn/tutorials/gas-estimation.md b/snaps/learn/tutorials/gas-estimation.md index 1e9e44c5d9d..dc42f7edfb0 100644 --- a/snaps/learn/tutorials/gas-estimation.md +++ b/snaps/learn/tutorials/gas-estimation.md @@ -106,12 +106,12 @@ and add `iconPath` with the value `"images/gas.svg"` to point to your new icon: ```json title="snap.manifest.json" "location": { - "npm": { - "filePath": "dist/bundle.js", - "iconPath": "images/gas.svg", - "packageName": "snap", - "registry": "https://registry.npmjs.org/" - } + "npm": { + "filePath": "dist/bundle.js", + "iconPath": "images/gas.svg", + "packageName": "snap", + "registry": "https://registry.npmjs.org/" + } } ``` @@ -120,9 +120,9 @@ Edit the `files` array and add the `images/` folder: ```json title="package.json" "files": [ - "dist/", - "images/", - "snap.manifest.json" + "dist/", + "images/", + "snap.manifest.json" ], ``` @@ -134,12 +134,12 @@ permission by adding `"endowment:network-access": {}` to the `initialPermissions ```json title="snap.manifest.json" "initialPermissions": { - "snap_dialog": {}, - "endowment:rpc": { - "dapps": true, - "snaps": false - }, - "endowment:network-access": {} + "snap_dialog": {}, + "endowment:rpc": { + "dapps": true, + "snaps": false + }, + "endowment:network-access": {} }, "manifestVersion": "0.1" ``` @@ -157,8 +157,8 @@ import type { OnRpcRequestHandler } from "@metamask/snaps-sdk"; import { panel, text } from "@metamask/snaps-sdk"; async function getFees() { - const response = await fetch("https://beaconcha.in/api/v1/execution/gasnow"); - return response.text(); + const response = await fetch("https://beaconcha.in/api/v1/execution/gasnow"); + return response.text(); } ``` @@ -180,19 +180,19 @@ Update the `hello` method with the following code: ```typescript title="index.ts" case "hello": - return getFees().then(fees => { - return snap.request({ - method: 'snap_dialog', - params: { - type: "alert", - content: panel([ - text(`Hello, **${origin}**!`), - text("Current gas fee estimates:"), - copyable(fees), - ]), - } - }); + return getFees().then(fees => { + return snap.request({ + method: 'snap_dialog', + params: { + type: "alert", + content: panel([ + text(`Hello, **${origin}**!`), + text("Current gas fee estimates:"), + copyable(fees), + ]), + } }); + }); ``` ### 5. Build and test the Snap diff --git a/snaps/learn/tutorials/transaction-insights.md b/snaps/learn/tutorials/transaction-insights.md index c04a61baad6..32a9d8d0a16 100644 --- a/snaps/learn/tutorials/transaction-insights.md +++ b/snaps/learn/tutorials/transaction-insights.md @@ -86,8 +86,8 @@ permissions by modifying `initialPermissions`: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:transaction-insight": {}, - "endowment:ethereum-provider": {} + "endowment:transaction-insight": {}, + "endowment:ethereum-provider": {} } ``` @@ -108,40 +108,40 @@ import { heading, panel, text } from "@metamask/snaps-sdk"; // Handle outgoing transactions. export const onTransaction: OnTransactionHandler = async ({ transaction }) => { - // Use the Ethereum provider to fetch the gas price. - const currentGasPrice = await ethereum.request({ - method: "eth_gasPrice", - }) as string; - - // Get fields from the transaction object. - const transactionGas = parseInt(transaction.gas as string, 16); - const currentGasPriceInWei = parseInt(currentGasPrice ?? "", 16); - const maxFeePerGasInWei = parseInt(transaction.maxFeePerGas as string, 16); - const maxPriorityFeePerGasInWei = parseInt( - transaction.maxPriorityFeePerGas as string, - 16, - ); - - // Calculate gas fees the user would pay. - const gasFees = Math.min( - maxFeePerGasInWei * transactionGas, - (currentGasPriceInWei + maxPriorityFeePerGasInWei) * transactionGas, - ); - - // Calculate gas fees as percentage of transaction. - const transactionValueInWei = parseInt(transaction.value as string, 16); - const gasFeesPercentage = (gasFees / (gasFees + transactionValueInWei)) * 100; - - // Display percentage of gas fees in the transaction insights UI. - return { - content: panel([ - heading("Transaction insights Snap"), - text( - `As set up, you are paying **${gasFeesPercentage.toFixed(2)}%** - in gas fees for this transaction.`, - ), - ]), - }; + // Use the Ethereum provider to fetch the gas price. + const currentGasPrice = await ethereum.request({ + method: "eth_gasPrice", + }) as string; + + // Get fields from the transaction object. + const transactionGas = parseInt(transaction.gas as string, 16); + const currentGasPriceInWei = parseInt(currentGasPrice ?? "", 16); + const maxFeePerGasInWei = parseInt(transaction.maxFeePerGas as string, 16); + const maxPriorityFeePerGasInWei = parseInt( + transaction.maxPriorityFeePerGas as string, + 16, + ); + + // Calculate gas fees the user would pay. + const gasFees = Math.min( + maxFeePerGasInWei * transactionGas, + (currentGasPriceInWei + maxPriorityFeePerGasInWei) * transactionGas, + ); + + // Calculate gas fees as percentage of transaction. + const transactionValueInWei = parseInt(transaction.value as string, 16); + const gasFeesPercentage = (gasFees / (gasFees + transactionValueInWei)) * 100; + + // Display percentage of gas fees in the transaction insights UI. + return { + content: panel([ + heading("Transaction insights Snap"), + text( + `As set up, you are paying **${gasFeesPercentage.toFixed(2)}%** + in gas fees for this transaction.`, + ), + ]), + }; }; ``` @@ -193,14 +193,14 @@ For contract interactions, add the following code to the beginning of the `onTra ```typescript title="index.ts" if (typeof transaction.data === "string" && transaction.data !== "0x") { - return { - content: panel([ - heading("Percent Snap"), - text( - "This Snap only provides transaction insights for simple ETH transfers.", - ), - ]), - }; + return { + content: panel([ + heading("Percent Snap"), + text( + "This Snap only provides transaction insights for simple ETH transfers.", + ), + ]), + }; } ``` diff --git a/snaps/reference/cli/options.md b/snaps/reference/cli/options.md index cfa262ca5bd..908c31ff57f 100644 --- a/snaps/reference/cli/options.md +++ b/snaps/reference/cli/options.md @@ -59,16 +59,16 @@ customizeWebpackConfig: , ```typescript customizeWebpackConfig: (config) => - merge(config, { - plugins: [ - // Add a plugin. - ], - module: { - rules: [ - // Add a loader. - ], - }, - }), + merge(config, { + plugins: [ + // Add a plugin. + ], + module: { + rules: [ + // Add a loader. + ], + }, + }), ``` @@ -96,8 +96,8 @@ environment: , ```javascript environment: { - SNAP_ENV: process.env.SNAP_ENV, - PUBLIC_KEY: process.env.PUBLIC_KEY, + SNAP_ENV: process.env.SNAP_ENV, + PUBLIC_KEY: process.env.PUBLIC_KEY, }, ``` @@ -146,7 +146,7 @@ These features are not stable, and might change in the future. ```javascript experimental: { - wasm: , + wasm: , }, ``` @@ -155,7 +155,7 @@ experimental: { ```javascript experimental: { - wasm: true, + wasm: true, }, ``` @@ -182,7 +182,7 @@ import program from "./program.wasm"; ```javascript features: { - images: , + images: , }, ``` @@ -191,7 +191,7 @@ features: { ```javascript features: { - images: false, + images: false, }, ``` @@ -235,7 +235,7 @@ The Snap [manifest file](../../learn/about-snaps/files.md#manifest-file) configu ```javascript manifest: { - path: , + path: , }, ``` @@ -244,7 +244,7 @@ manifest: { ```javascript manifest: { - path: "snap.manifest.json", + path: "snap.manifest.json", }, ``` @@ -261,7 +261,7 @@ The default is `"snap.manifest.json"`. ```javascript manifest: { - update: , + update: , }, ``` @@ -270,7 +270,7 @@ manifest: { ```javascript manifest: { - update: false, + update: false, }, ``` @@ -292,7 +292,7 @@ The output configuration. ```javascript output: { - clean: , + clean: , }, ``` @@ -301,7 +301,7 @@ output: { ```javascript output: { - clean: true, + clean: true, }, ``` @@ -318,7 +318,7 @@ The default is `false`. ```javascript output: { - filename: , + filename: , }, ``` @@ -327,7 +327,7 @@ output: { ```javascript output: { - filename: "bundle.js", + filename: "bundle.js", }, ``` @@ -344,7 +344,7 @@ The default is `"bundle.js"`. ```javascript output: { - minimize: , + minimize: , }, ``` @@ -353,7 +353,7 @@ output: { ```javascript output: { - minimize: false, + minimize: false, }, ``` @@ -371,7 +371,7 @@ The default is `true`. ```javascript output: { - path: , + path: , }, ``` @@ -380,7 +380,7 @@ output: { ```javascript output: { - path: "dist", + path: "dist", }, ``` @@ -404,9 +404,9 @@ polyfills: ```javascript polyfills: { - buffer: true, - crypto: true, - path: true, + buffer: true, + crypto: true, + path: true, } ``` @@ -433,7 +433,7 @@ The development server is used to test the Snap during development, using the ```javascript server: { - enabled: , + enabled: , }, ``` @@ -442,7 +442,7 @@ server: { ```javascript server: { - enabled: false, + enabled: false, }, ``` @@ -458,7 +458,7 @@ Enables or disables the development server. ```javascript server: { - port: , + port: , }, ``` @@ -467,7 +467,7 @@ server: { ```javascript server: { - port: 9000, + port: 9000, }, ``` @@ -485,7 +485,7 @@ The default is `8081`. ```javascript server: { - root: , + root: , }, ``` @@ -494,7 +494,7 @@ server: { ```javascript server: { - root: "snap", + root: "snap", }, ``` @@ -540,7 +540,7 @@ The stats configuration, which controls the log output of the CLI. ```javascript stats: { - buffer: , + buffer: , }, ``` @@ -549,7 +549,7 @@ stats: { ```javascript stats: { - buffer: false, + buffer: false, }, ``` @@ -569,7 +569,7 @@ The default is `true`. ```javascript stats: { - builtIns: , + builtIns: , }, ``` @@ -578,11 +578,11 @@ stats: { ```javascript stats: { - builtIns: { - ignore: [ - // Built-in modules to ignore. - ], - }, + builtIns: { + ignore: [ + // Built-in modules to ignore. + ], + }, }, ``` @@ -608,7 +608,7 @@ The default is an empty ignore list. ```javascript stats: { - verbose: , + verbose: , }, ``` @@ -617,7 +617,7 @@ stats: { ```javascript stats: { - verbose: true, + verbose: true, }, ``` diff --git a/snaps/reference/entry-points.md b/snaps/reference/entry-points.md index cff5aa64d85..10ece2a0497 100644 --- a/snaps/reference/entry-points.md +++ b/snaps/reference/entry-points.md @@ -34,19 +34,19 @@ An object containing an RPC request specified in the `endowment:cronjob` permiss import type { OnCronjobHandler } from "@metamask/snaps-sdk"; export const onCronjob: OnCronjobHandler = async ({ request }) => { - switch (request.method) { - case "exampleMethodOne": - return snap.request({ - method: "snap_notify", - params: { - type: "inApp", - message: "Hello, world!", - }, - }); - - default: - throw new Error("Method not found."); - } + switch (request.method) { + case "exampleMethodOne": + return snap.request({ + method: "snap_notify", + params: { + type: "inApp", + message: "Hello, world!", + }, + }); + + default: + throw new Error("Method not found."); + } }; ``` @@ -55,19 +55,19 @@ export const onCronjob: OnCronjobHandler = async ({ request }) => { ```js title="index.js" module.exports.onCronjob = async ({ request }) => { - switch (request.method) { - case "exampleMethodOne": - return snap.request({ - method: "snap_notify", - params: { - type: "inApp", - message: "Hello, world!", - }, - }); - - default: - throw new Error("Method not found."); - } + switch (request.method) { + case "exampleMethodOne": + return snap.request({ + method: "snap_notify", + params: { + type: "inApp", + message: "Hello, world!", + }, + }); + + default: + throw new Error("Method not found."); + } }; ``` @@ -107,12 +107,12 @@ import type { OnHomePageHandler } from "@metamask/snaps-sdk"; import { panel, text, heading } from "@metamask/snaps-sdk"; export const onHomePage: OnHomePageHandler = async () => { - return { - content: panel([ - heading("Hello world!"), - text("Welcome to my Snap home page!"), - ]), - }; + return { + content: panel([ + heading("Hello world!"), + text("Welcome to my Snap home page!"), + ]), + }; }; ``` @@ -123,12 +123,12 @@ export const onHomePage: OnHomePageHandler = async () => { import { panel, text, heading } from "@metamask/snaps-sdk"; module.exports.onHomePage = async () => { - return { - content: panel([ - heading("Hello world!"), - text("Welcome to my Snap home page!"), - ]), - }; + return { + content: panel([ + heading("Hello world!"), + text("Welcome to my Snap home page!"), + ]), + }; }; ``` @@ -160,18 +160,18 @@ import type { OnInstallHandler } from "@metamask/snaps-sdk"; import { heading, panel, text } from "@metamask/snaps-sdk"; export const onInstall: OnInstallHandler = async () => { - await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Thank you for installing my Snap"), - text( - "To use this Snap, visit the companion dapp at [metamask.io](https://metamask.io).", - ), - ]), - }, - }); + await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Thank you for installing my Snap"), + text( + "To use this Snap, visit the companion dapp at [metamask.io](https://metamask.io).", + ), + ]), + }, + }); }; ``` @@ -182,18 +182,18 @@ export const onInstall: OnInstallHandler = async () => { import { heading, panel, text } from "@metamask/snaps-sdk"; module.exports.onInstall = async () => { - await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Thank you for installing my Snap"), - text( - "To use this Snap, visit the companion dapp at [metamask.io](https://metamask.io).", - ), - ]), - }, - }); + await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Thank you for installing my Snap"), + text( + "To use this Snap, visit the companion dapp at [metamask.io](https://metamask.io).", + ), + ]), + }, + }); }; ``` @@ -231,23 +231,23 @@ An object containing: import type { OnNameLookupHandler } from "@metamask/snaps-sdk"; export const onNameLookup: OnNameLookupHandler = async (request) => { - const { chainId, address, domain } = request; - - if (address) { - const shortAddress = address.substring(2, 5); - const chainIdDecimal = parseInt(chainId.split(":")[1], 10); - const resolvedDomain = `${shortAddress}.${chainIdDecimal}.test.domain`; - return { resolvedDomains: [{ resolvedDomain, protocol: "test protocol" }] }; - } - - if (domain) { - const resolvedAddress = "0xc0ffee254729296a45a3885639AC7E10F9d54979"; - return { - resolvedAddresses: [{ resolvedAddress, protocol: "test protocol" }], - }; - } - - return null; + const { chainId, address, domain } = request; + + if (address) { + const shortAddress = address.substring(2, 5); + const chainIdDecimal = parseInt(chainId.split(":")[1], 10); + const resolvedDomain = `${shortAddress}.${chainIdDecimal}.test.domain`; + return { resolvedDomains: [{ resolvedDomain, protocol: "test protocol" }] }; + } + + if (domain) { + const resolvedAddress = "0xc0ffee254729296a45a3885639AC7E10F9d54979"; + return { + resolvedAddresses: [{ resolvedAddress, protocol: "test protocol" }], + }; + } + + return null; }; ``` @@ -256,23 +256,23 @@ export const onNameLookup: OnNameLookupHandler = async (request) => { ```js title="index.js" module.exports.onNameLookup = async ({ request }) => { - const { chainId, address, domain } = request; - - if (address) { - const shortAddress = address.substring(2, 5); - const chainIdDecimal = parseInt(chainId.split(":")[1], 10); - const resolvedDomain = `${shortAddress}.${chainIdDecimal}.test.domain`; - return { resolvedDomains: [{ resolvedDomain, protocol: "test protocol" }] }; - } - - if (domain) { - const resolvedAddress = "0xc0ffee254729296a45a3885639AC7E10F9d54979"; - return { - resolvedAddresses: [{ resolvedAddress, protocol: "test protocol" }], - }; - } - - return null; + const { chainId, address, domain } = request; + + if (address) { + const shortAddress = address.substring(2, 5); + const chainIdDecimal = parseInt(chainId.split(":")[1], 10); + const resolvedDomain = `${shortAddress}.${chainIdDecimal}.test.domain`; + return { resolvedDomains: [{ resolvedDomain, protocol: "test protocol" }] }; + } + + if (domain) { + const resolvedAddress = "0xc0ffee254729296a45a3885639AC7E10F9d54979"; + return { + resolvedAddresses: [{ resolvedAddress, protocol: "test protocol" }], + }; + } + + return null; }; ``` @@ -383,18 +383,18 @@ import type { OnSignatureHandler, SeverityLevel } from "@metamask/snaps-sdk"; import { panel, heading, text } from "@metamask/snaps-sdk"; export const onSignature: OnSignatureHandler = async ({ - signature, - signatureOrigin, + signature, + signatureOrigin, }) => { - const insights = /* Get insights */; - return { - content: panel([ - heading("My Signature Insights"), - text("Here are the insights:"), - ...(insights.map((insight) => text(insight.value))), - ]), - severity: SeverityLevel.Critical, - }; + const insights = /* Get insights */; + return { + content: panel([ + heading("My Signature Insights"), + text("Here are the insights:"), + ...(insights.map((insight) => text(insight.value))), + ]), + severity: SeverityLevel.Critical, + }; }; ``` @@ -406,18 +406,18 @@ import { SeverityLevel } from "@metamask/snaps-sdk"; import { panel, heading, text } from "@metamask/snaps-sdk"; module.exports.onSignature = async ({ - signature, - signatureOrigin, + signature, + signatureOrigin, }) => { - const insights = /* Get insights */; - return { - content: panel([ - heading("My Signature Insights"), - text("Here are the insights:"), - ...(insights.map((insight) => text(insight.value))), - ]), - severity: SeverityLevel.Critical, - }; + const insights = /* Get insights */; + return { + content: panel([ + heading("My Signature Insights"), + text("Here are the insights:"), + ...(insights.map((insight) => text(insight.value))), + ]), + severity: SeverityLevel.Critical, + }; }; ``` @@ -466,18 +466,18 @@ import type { OnTransactionHandler } from "@metamask/snaps-sdk"; import { panel, heading, text } from "@metamask/snaps-sdk"; export const onTransaction: OnTransactionHandler = async ({ - transaction, - chainId, - transactionOrigin, + transaction, + chainId, + transactionOrigin, }) => { - const insights = /* Get insights */; - return { - content: panel([ - heading("My Transaction Insights"), - text("Here are the insights:"), - ...(insights.map((insight) => text(insight.value))), - ]), - }; + const insights = /* Get insights */; + return { + content: panel([ + heading("My Transaction Insights"), + text("Here are the insights:"), + ...(insights.map((insight) => text(insight.value))), + ]), + }; }; ``` @@ -488,18 +488,18 @@ export const onTransaction: OnTransactionHandler = async ({ import { panel, heading, text } from "@metamask/snaps-sdk"; module.exports.onTransaction = async ({ - transaction, - chainId, - transactionOrigin, + transaction, + chainId, + transactionOrigin, }) => { - const insights = /* Get insights */; - return { - content: panel([ - heading("My Transaction Insights"), - text("Here are the insights:"), - ...(insights.map((insight) => text(insight.value))), - ]), - }; + const insights = /* Get insights */; + return { + content: panel([ + heading("My Transaction Insights"), + text("Here are the insights:"), + ...(insights.map((insight) => text(insight.value))), + ]), + }; }; ``` @@ -524,20 +524,20 @@ import type { OnTransactionHandler } from "@metamask/snaps-sdk"; import { panel, heading, text } from "@metamask/snaps-sdk"; export const onTransaction: OnTransactionHandler = async ({ - transaction, - chainId, - transactionOrigin, + transaction, + chainId, + transactionOrigin, }) => { - const insights = /* Get insights */; - return { - content: panel([ - heading("My Transaction Insights"), - text("Here are the insights:"), - ...(insights.map((insight) => text(insight.value))), - ]), - // highlight-next-line - severity: "critical", - }; + const insights = /* Get insights */; + return { + content: panel([ + heading("My Transaction Insights"), + text("Here are the insights:"), + ...(insights.map((insight) => text(insight.value))), + ]), + // highlight-next-line + severity: "critical", + }; }; ``` @@ -548,20 +548,20 @@ export const onTransaction: OnTransactionHandler = async ({ import { panel, heading, text } from "@metamask/snaps-sdk"; module.exports.onTransaction = async ({ - transaction, - chainId, - transactionOrigin, + transaction, + chainId, + transactionOrigin, }) => { - const insights = /* Get insights */; - return { - content: panel([ - heading("My Transaction Insights"), - text("Here are the insights:"), - ...(insights.map((insight) => text(insight.value))), - ]), - // highlight-next-line - severity: "critical", - }; + const insights = /* Get insights */; + return { + content: panel([ + heading("My Transaction Insights"), + text("Here are the insights:"), + ...(insights.map((insight) => text(insight.value))), + ]), + // highlight-next-line + severity: "critical", + }; }; ``` @@ -593,21 +593,21 @@ import type { OnUpdateHandler } from "@metamask/snaps-sdk"; import { heading, panel, text } from "@metamask/snaps-sdk"; export const onUpdate: OnUpdateHandler = async () => { - await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Thank you for updating my Snap"), - text( - "New features added in this version:", - ), - text( - "Added a dialog that appears when updating." - ), - ]), - }, - }); + await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Thank you for updating my Snap"), + text( + "New features added in this version:", + ), + text( + "Added a dialog that appears when updating." + ), + ]), + }, + }); }; ``` @@ -618,21 +618,21 @@ export const onUpdate: OnUpdateHandler = async () => { import { heading, panel, text } from "@metamask/snaps-sdk"; module.exports.onUpdate = async () => { - await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Thank you for updating my Snap"), - text( - "New features added in this version:", - ), - text( - "Added a dialog that appears when updating." - ), - ]), - }, - }); + await snap.request({ + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Thank you for updating my Snap"), + text( + "New features added in this version:", + ), + text( + "Added a dialog that appears when updating." + ), + ]), + }, + }); }; ``` @@ -667,9 +667,9 @@ import type { OnUserInputHandler } from "@metamask/snaps-sdk"; import { UserInputEventType } from "@metamask/snaps-sdk"; export const onUserInput: OnUserInputHandler = async ({ id, event }) => { - if (event.type === UserInputEventType.FormSubmitEvent) { - console.log("The submitted form values are", event.value); - } + if (event.type === UserInputEventType.FormSubmitEvent) { + console.log("The submitted form values are", event.value); + } }; ``` @@ -680,9 +680,9 @@ export const onUserInput: OnUserInputHandler = async ({ id, event }) => { const { UserInputEventType } = require("@metamask/snaps-sdk"); module.exports.onUserInput = async ({ id, event }) => { - if (event.type === UserInputEventType.FormSubmitEvent) { - console.log("The submitted form values are", event.value); - } + if (event.type === UserInputEventType.FormSubmitEvent) { + console.log("The submitted form values are", event.value); + } }; ``` diff --git a/snaps/reference/jest.md b/snaps/reference/jest.md index 8bc20d9d95a..05fe7c1c393 100644 --- a/snaps/reference/jest.md +++ b/snaps/reference/jest.md @@ -31,10 +31,10 @@ An object with functions that can be used to interact with the Snap. import { installSnap } from "@metamask/snaps-jest"; describe("MySnap", () => { - it("should do something", async () => { - await installSnap(/* optional Snap ID */); - // ... - }); + it("should do something", async () => { + await installSnap(/* optional Snap ID */); + // ... + }); }); ``` @@ -57,20 +57,20 @@ which can be checked using [Jest matchers](#jest-matchers). import { installSnap } from "@metamask/snaps-jest"; describe("MySnap", () => { - it("should respond to foo with bar", async () => { - const { request } = await installSnap(/* optional snap ID */); - const response = await request({ - origin: "http://localhost:8080", - method: "foo", - params: [], - }); - - /* Check the response using Jest matchers. Since the response is a standard JSON-RPC response, - * you can use any standard Jest matchers to check it, including snapshot matchers. */ - expect(response).toRespondWith("bar"); - expect(response).not.toRespondWithError("baz"); - expect(response).toMatchSnapshot(); + it("should respond to foo with bar", async () => { + const { request } = await installSnap(/* Optional snap ID */); + const response = await request({ + origin: "http://localhost:8080", + method: "foo", + params: [], }); + + /* Check the response using Jest matchers. Since the response is a standard JSON-RPC response, + * you can use any standard Jest matchers to check it, including snapshot matchers. */ + expect(response).toRespondWith("bar"); + expect(response).not.toRespondWithError("baz"); + expect(response).toMatchSnapshot(); + }); }); ``` @@ -109,19 +109,19 @@ import { installSnap } from "@metamask/snaps-jest"; import { panel, text } from "@metamask/snaps-sdk"; describe("MySnap", () => { - it("should return insights", async () => { - const { onTransaction } = await installSnap(/* optional Snap ID */); - const response = await onTransaction({ - value: "0x0", - data: "0x", - gasLimit: "0x5208", - maxFeePerGas: "0x5208", - maxPriorityFeePerGas: "0x5208", - nonce: "0x0", - }); - - expect(response).toRender(panel([text("Hello, world!")])); + it("should return insights", async () => { + const { onTransaction } = await installSnap(/* Optional Snap ID */); + const response = await onTransaction({ + value: "0x0", + data: "0x", + gasLimit: "0x5208", + maxFeePerGas: "0x5208", + maxPriorityFeePerGas: "0x5208", + nonce: "0x0", }); + + expect(response).toRender(panel([text("Hello, world!")])); + }); }); ``` @@ -147,17 +147,17 @@ which can be checked using [Jest matchers](#jest-matchers). import { installSnap } from "@metamask/snaps-jest"; describe("MySnap", () => { - it("should end foo cronjobs with response bar", async () => { - const { onCronjob } = await installSnap(/* optional snap ID */); - const response = await onCronjob({ - method: "foo", - params: [], - }); - - // Check the response using Jest matchers. - expect(response).toRespondWith("bar"); - expect(response).not.toRespondWithError("baz"); + it("should end foo cronjobs with response bar", async () => { + const { onCronjob } = await installSnap(/* Optional snap ID */); + const response = await onCronjob({ + method: "foo", + params: [], }); + + // Check the response using Jest matchers. + expect(response).toRespondWith("bar"); + expect(response).not.toRespondWithError("baz"); + }); }); ``` @@ -173,12 +173,12 @@ import { installSnap } from "@metamask/snaps-jest"; import { panel, text } from "@metamask/snaps-sdk"; describe("MySnap", () => { - it("should render the home page", async () => { - const { onHomePage } = await installSnap(/* optional snap ID */); - const response = await onHomePage(); - - expect(response).toRender(panel([text("Hello, world!")])); - }); + it("should render the home page", async () => { + const { onHomePage } = await installSnap(/* Optional snap ID */); + const response = await onHomePage(); + + expect(response).toRender(panel([text("Hello, world!")])); + }); }); ``` @@ -201,27 +201,27 @@ import { text } from "@metamask/snaps-sdk"; import { assert } from "@metamask/utils"; describe("MySnap", () => { - it("should render an alert with hello world", async () => { - const { request } = await installSnap(/* optional Snap ID */); - - // Note: You cannot resolve the promise yet! - const response = request({ - method: "foo", - }); - - const ui = await response.getInterface(); - - // This is useful if you're using TypeScript, since it infers the type of the user interface. - assert(ui.type === "alert"); - expect(ui).toRender(text("Hello, world!")); - - // Select the OK button. - await ui.ok(); - - // Now you can resolve the promise. - const result = await response; - expect(result).toRespondWith("bar"); + it("should render an alert with hello world", async () => { + const { request } = await installSnap(/* Optional Snap ID */); + + // Note: You cannot resolve the promise yet! + const response = request({ + method: "foo", }); + + const ui = await response.getInterface(); + + // This is useful if you're using TypeScript, since it infers the type of the user interface. + assert(ui.type === "alert"); + expect(ui).toRender(text("Hello, world!")); + + // Select the OK button. + await ui.ok(); + + // Now you can resolve the promise. + const result = await response; + expect(result).toRespondWith("bar"); + }); }); ``` @@ -267,12 +267,12 @@ The server options are: ```javascript title="jest.config.js" module.exports = { - preset: "@metamask/snaps-jest", - testEnvironmentOptions: { - server: { - port: 8080, - root: "/path/to/snap/files", - }, + preset: "@metamask/snaps-jest", + testEnvironmentOptions: { + server: { + port: 8080, + root: "/path/to/snap/files", }, + }, }; ``` diff --git a/snaps/reference/keyring-api/account-management/events.md b/snaps/reference/keyring-api/account-management/events.md index 26865b0df87..73db7282a5a 100644 --- a/snaps/reference/keyring-api/account-management/events.md +++ b/snaps/reference/keyring-api/account-management/events.md @@ -19,10 +19,10 @@ MetaMask returns an error if the account already exists or the account object is ```typescript try { - emitSnapKeyringEvent(snap, KeyringEvent.AccountCreated, { account }); - // Update your Snap's state. + emitSnapKeyringEvent(snap, KeyringEvent.AccountCreated, { account }); + // Update your Snap's state. } catch (error) { - // Handle the error. + // Handle the error. } ``` @@ -39,10 +39,10 @@ MetaMask returns an error if one of the following is true: ```typescript try { - emitSnapKeyringEvent(snap, KeyringEvent.AccountUpdated, { account }); - // Update your Snap's state. + emitSnapKeyringEvent(snap, KeyringEvent.AccountUpdated, { account }); + // Update your Snap's state. } catch (error) { - // Handle the error. + // Handle the error. } ``` @@ -55,12 +55,12 @@ The delete event is idempotent, so it is safe to emit even if the account does n ```typescript try { - emitSnapKeyringEvent(snap, KeyringEvent.AccountDeleted, { - id: account.id, - }); - // Update your Snap's state. + emitSnapKeyringEvent(snap, KeyringEvent.AccountDeleted, { + id: account.id, + }); + // Update your Snap's state. } catch (error) { - // Handle the error. + // Handle the error. } ``` @@ -75,13 +75,13 @@ This event only applies to Snaps that ```typescript try { - emitSnapKeyringEvent(snap, KeyringEvent.RequestApproved, { - id: request.id, - result, - }); - // Update your Snap's state. + emitSnapKeyringEvent(snap, KeyringEvent.RequestApproved, { + id: request.id, + result, + }); + // Update your Snap's state. } catch (error) { - // Handle the error. + // Handle the error. } ``` @@ -96,11 +96,11 @@ This event only applies to Snaps that ```typescript try { - emitSnapKeyringEvent(snap, KeyringEvent.RequestRejected, { - id: request.id, - }); - // Update your Snap's state. + emitSnapKeyringEvent(snap, KeyringEvent.RequestRejected, { + id: request.id, + }); + // Update your Snap's state. } catch (error) { - // Handle the error. + // Handle the error. } ``` diff --git a/snaps/reference/keyring-api/account-management/index.md b/snaps/reference/keyring-api/account-management/index.md index 3dee67b0765..8bc84bf301c 100644 --- a/snaps/reference/keyring-api/account-management/index.md +++ b/snaps/reference/keyring-api/account-management/index.md @@ -39,13 +39,13 @@ An object containing: ```json { - "method": "keyring_createAccount", - "params": { - "options": { - "signerCount": 5, - "threshold": 3 - } + "method": "keyring_createAccount", + "params": { + "options": { + "signerCount": 5, + "threshold": 3 } + } } ``` @@ -54,19 +54,19 @@ An object containing: ```json { - "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", - "methods": [ - "eth_sign", - "eth_signTransaction", - "eth_signTypedData_v4", - "personal_sign" - ], - "options": { - "signerCount": 5, - "threshold": 3 - }, - "type": "eip155:eoa" + "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", + "methods": [ + "eth_sign", + "eth_signTransaction", + "eth_signTypedData_v4", + "personal_sign" + ], + "options": { + "signerCount": 5, + "threshold": 3 + }, + "type": "eip155:eoa" } ``` @@ -94,10 +94,10 @@ An object containing: ```json { - "method": "keyring_deleteAccount", - "params": { - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a" - } + "method": "keyring_deleteAccount", + "params": { + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a" + } } ``` @@ -135,10 +135,10 @@ An object containing: ```json { - "method": "keyring_exportAccount", - "params": { - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a" - } + "method": "keyring_exportAccount", + "params": { + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a" + } } ``` @@ -147,7 +147,7 @@ An object containing: ```json { - "privateKey": "66a41d66be6483f1fdfd01fdb66173d449594bbd286149b019504dd72b58bc51" + "privateKey": "66a41d66be6483f1fdfd01fdb66173d449594bbd286149b019504dd72b58bc51" } ``` @@ -180,16 +180,16 @@ An object containing: ```json { - "method": "keyring_filterAccountChains", - "params": { - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", - "chains": [ - "eip155:W", - "eip155:X", - "eip155:Y", - "eip155:Z" - ] - } + "method": "keyring_filterAccountChains", + "params": { + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", + "chains": [ + "eip155:W", + "eip155:X", + "eip155:Y", + "eip155:Z" + ] + } } ``` @@ -198,10 +198,10 @@ An object containing: ```json { - "chains": [ - "eip155:X", - "eip155:Y" - ] + "chains": [ + "eip155:X", + "eip155:Y" + ] } ``` @@ -229,10 +229,10 @@ An object containing: ```json { - "method": "keyring_getAccount", - "params": { - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a" - } + "method": "keyring_getAccount", + "params": { + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a" + } } ``` @@ -241,19 +241,19 @@ An object containing: ```json { - "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", - "methods": [ - "eth_sign", - "eth_signTransaction", - "eth_signTypedData_v4", - "personal_sign" - ], - "options": { - "signerCount": 5, - "threshold": 3 - }, - "type": "eip155:eoa" + "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", + "methods": [ + "eth_sign", + "eth_signTransaction", + "eth_signTypedData_v4", + "personal_sign" + ], + "options": { + "signerCount": 5, + "threshold": 3 + }, + "type": "eip155:eoa" } ``` @@ -288,31 +288,31 @@ An array of [account objects](objects.md#keyringaccount) handled by the Snap. ```json [ - { - "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", - "methods": [ - "eth_sign", - "eth_signTransaction", - "eth_signTypedData_v4", - "personal_sign" - ], - "options": { - "signerCount": 5, - "threshold": 3 - }, - "type": "eip155:eoa" + { + "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", + "methods": [ + "eth_sign", + "eth_signTransaction", + "eth_signTypedData_v4", + "personal_sign" + ], + "options": { + "signerCount": 5, + "threshold": 3 }, - { - "address": "0x84674cffb6146d19b986fc88ec70a441b570a45b", - "id": "17a87b4a-286c-444d-aebb-1fed89021419", - "methods": [ - "eth_prepareUserOperation", - "eth_patchUserOperation", - "eth_signUserOperation" - ], - "type": "eip155:erc4337" - } + "type": "eip155:eoa" + }, + { + "address": "0x84674cffb6146d19b986fc88ec70a441b570a45b", + "id": "17a87b4a-286c-444d-aebb-1fed89021419", + "methods": [ + "eth_prepareUserOperation", + "eth_patchUserOperation", + "eth_signUserOperation" + ], + "type": "eip155:erc4337" + } ] ``` @@ -338,22 +338,22 @@ Updates an account. ```json { - "method": "keyring_updateAccount", - "params": { - "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", - "methods": [ - "eth_sign", - "eth_signTransaction", - "eth_signTypedData_v4", - "personal_sign" - ], - "options": { - "signerCount": 7, - "threshold": 4 - }, - "type": "eip155:eoa" - } + "method": "keyring_updateAccount", + "params": { + "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", + "methods": [ + "eth_sign", + "eth_signTransaction", + "eth_signTypedData_v4", + "personal_sign" + ], + "options": { + "signerCount": 7, + "threshold": 4 + }, + "type": "eip155:eoa" + } } ``` @@ -393,10 +393,10 @@ An object containing: ```json { - "method": "keyring_approveRequest", - "params": { - "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4" - } + "method": "keyring_approveRequest", + "params": { + "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4" + } } ``` @@ -431,10 +431,10 @@ An object containing: ```json { - "method": "keyring_getRequest", - "params": { - "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4" - } + "method": "keyring_getRequest", + "params": { + "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4" + } } ``` @@ -443,16 +443,16 @@ An object containing: ```json { - "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4", - "request": { - "method": "personal_sign", - "params": [ - "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", - "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1" - ] - }, - "scope": "eip155:1" + "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4", + "request": { + "method": "personal_sign", + "params": [ + "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", + "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1" + ] + }, + "scope": "eip155:1" } ``` @@ -487,37 +487,37 @@ An array of pending [request objects](objects.md#keyringrequest). ```json [ - { - "account": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4", - "request": { - "method": "personal_sign", - "params": [ - "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", - "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1" - ] - }, - "scope": "eip155:1" + { + "account": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4", + "request": { + "method": "personal_sign", + "params": [ + "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", + "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1" + ] }, - { - "account": "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1", - "id": "f6f302ae-38d7-4b95-ae88-bf2fb7fbee87", - "request": { - "method": "eth_sendTransaction", - "params": [ - { - "from": "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1", - "nonce": "0x1", - "gasPrice": "0x10", - "gasLimit": "0x5208", - "to": "0x84674cffb6146d19b986fc88ec70a441b570a45b", - "value": "0x10000", - "data": "0x" - } - ] - }, - "scope": "eip155:1" - } + "scope": "eip155:1" + }, + { + "account": "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1", + "id": "f6f302ae-38d7-4b95-ae88-bf2fb7fbee87", + "request": { + "method": "eth_sendTransaction", + "params": [ + { + "from": "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1", + "nonce": "0x1", + "gasPrice": "0x10", + "gasLimit": "0x5208", + "to": "0x84674cffb6146d19b986fc88ec70a441b570a45b", + "value": "0x10000", + "data": "0x" + } + ] + }, + "scope": "eip155:1" + } ] ``` @@ -545,10 +545,10 @@ An object containing: ```json { - "method": "keyring_rejectRequest", - "params": { - "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4" - } + "method": "keyring_rejectRequest", + "params": { + "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4" + } } ``` @@ -593,19 +593,19 @@ If the request is [asynchronous](../../../features/custom-evm-accounts/index.md# ```json { - "method": "keyring_submitRequest", - "params": { - "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4", - "request": { - "method": "personal_sign", - "params": [ - "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", - "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1" - ] - }, - "scope": "eip155:1" - } + "method": "keyring_submitRequest", + "params": { + "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4", + "request": { + "method": "personal_sign", + "params": [ + "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", + "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1" + ] + }, + "scope": "eip155:1" + } } ``` @@ -614,8 +614,8 @@ If the request is [asynchronous](../../../features/custom-evm-accounts/index.md# ```json { - "pending": false, - "result": "0x9aef363b17bc18dfbdcb9ed3ce5f9f96788ce84b353d262099e90c4fa0b513a4e21ee47bafa04c0630750e901b62bd4839b45219c191ec6076d6549637cb1beb4c" + "pending": false, + "result": "0x9aef363b17bc18dfbdcb9ed3ce5f9f96788ce84b353d262099e90c4fa0b513a4e21ee47bafa04c0630750e901b62bd4839b45219c191ec6076d6549637cb1beb4c" } ``` diff --git a/snaps/reference/keyring-api/account-management/objects.md b/snaps/reference/keyring-api/account-management/objects.md index d226b714bd9..d5e4c59293c 100644 --- a/snaps/reference/keyring-api/account-management/objects.md +++ b/snaps/reference/keyring-api/account-management/objects.md @@ -27,19 +27,19 @@ An account object contains: ```json { - "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", - "methods": [ - "eth_sign", - "eth_signTransaction", - "eth_signTypedData_v4", - "personal_sign" - ], - "options": { - "signerCount": 5, - "threshold": 3 - }, - "type": "eip155:eoa" + "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "091bbc2e-6625-44d0-ac5c-658670ca649a", + "methods": [ + "eth_sign", + "eth_signTransaction", + "eth_signTypedData_v4", + "personal_sign" + ], + "options": { + "signerCount": 5, + "threshold": 3 + }, + "type": "eip155:eoa" } ``` @@ -60,15 +60,15 @@ A request object contains: ```json { - "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", - "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4", - "request": { - "method": "personal_sign", - "params": [ - "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", - "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1" - ] - }, - "scope": "eip155:1" + "address": "0xd1f5279be4b4dd94133a23dee1b23f5bfc0db1d0", + "id": "f84d3a97-b6e1-47ea-8b0c-fd8609efaad4", + "request": { + "method": "personal_sign", + "params": [ + "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", + "0xe887f3b50232722e6eb4c1d3a03b34c9b345acd1" + ] + }, + "scope": "eip155:1" } ``` diff --git a/snaps/reference/keyring-api/chain-methods.md b/snaps/reference/keyring-api/chain-methods.md index 70788210824..830799d35ea 100644 --- a/snaps/reference/keyring-api/chain-methods.md +++ b/snaps/reference/keyring-api/chain-methods.md @@ -40,11 +40,11 @@ Signature: `string` - Hex-encoded signature. ```json { - "method": "personal_sign", - "params": [ - "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", - "0x5874174dcf1ab6F7Efd8496f4f09404CD1c5bA84" - ] + "method": "personal_sign", + "params": [ + "0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765", + "0x5874174dcf1ab6F7Efd8496f4f09404CD1c5bA84" + ] } ``` @@ -99,22 +99,22 @@ A signature object containing: ```json { - "method": "eth_signTransaction", - "params": [ - { - "type": "0x2", - "nonce": "0x1", - "to": "0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb", - "from": "0x660265edc169bab511a40c0e049cc1e33774443d", - "value": "0x0", - "data": "0x", - "gasLimit": "0x5208", - "maxPriorityFeePerGas": "0x3b9aca00", - "maxFeePerGas": "0x2540be400", - "accessList": [], - "chainId": "0xaa36a7" - } - ] + "method": "eth_signTransaction", + "params": [ + { + "type": "0x2", + "nonce": "0x1", + "to": "0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb", + "from": "0x660265edc169bab511a40c0e049cc1e33774443d", + "value": "0x0", + "data": "0x", + "gasLimit": "0x5208", + "maxPriorityFeePerGas": "0x3b9aca00", + "maxFeePerGas": "0x2540be400", + "accessList": [], + "chainId": "0xaa36a7" + } + ] } ``` @@ -123,20 +123,20 @@ A signature object containing: ```json { - "method": "eth_signTransaction", - "params": [ - { - "type": "0x0", - "nonce": "0x0", - "to": "0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb", - "from": "0x660265edc169bab511a40c0e049cc1e33774443d", - "value": "0x0", - "data": "0x", - "gasLimit": "0x5208", - "gasPrice": "0x2540be400", - "chainId": "0xaa36a7" - } - ] + "method": "eth_signTransaction", + "params": [ + { + "type": "0x0", + "nonce": "0x0", + "to": "0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb", + "from": "0x660265edc169bab511a40c0e049cc1e33774443d", + "value": "0x0", + "data": "0x", + "gasLimit": "0x5208", + "gasPrice": "0x2540be400", + "chainId": "0xaa36a7" + } + ] } ``` @@ -145,9 +145,9 @@ A signature object containing: ```json { - "v": "0x1", - "r": "0x51991c5099327d3c7eaa745de60c52a93555e5cbc418eb9b405fe92d986dee08", - "s": "0x65b1d20a39360c31de69f872244e23a3549b702e11bc7d8eb3586812ac62be8d" + "v": "0x1", + "r": "0x51991c5099327d3c7eaa745de60c52a93555e5cbc418eb9b405fe92d986dee08", + "s": "0x65b1d20a39360c31de69f872244e23a3549b702e11bc7d8eb3586812ac62be8d" } ``` @@ -188,47 +188,47 @@ Signature: `string` - Hex-encoded signature. ```json { - "method": "eth_signTypedData_v4", - "params": [ - "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", - { - "types": { - "EIP712Domain": [ - { "name": "name", "type": "string" }, - { "name": "version", "type": "string" }, - { "name": "chainId", "type": "uint256" }, - { "name": "verifyingContract", "type": "address" } - ], - "Person": [ - { "name": "name", "type": "string" }, - { "name": "wallet", "type": "address" } - ], - "Mail": [ - { "name": "from", "type": "Person" }, - { "name": "to", "type": "Person" }, - { "name": "contents", "type": "string" } - ] - }, - "primaryType": "Mail", - "domain": { - "name": "Ether Mail", - "version": "1", - "chainId": 1, - "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" - }, - "message": { - "from": { - "name": "Cow", - "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" - }, - "to": { - "name": "Bob", - "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" - }, - "contents": "Hello, Bob!" - } - } - ] + "method": "eth_signTypedData_v4", + "params": [ + "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + { + "types": { + "EIP712Domain": [ + { "name": "name", "type": "string" }, + { "name": "version", "type": "string" }, + { "name": "chainId", "type": "uint256" }, + { "name": "verifyingContract", "type": "address" } + ], + "Person": [ + { "name": "name", "type": "string" }, + { "name": "wallet", "type": "address" } + ], + "Mail": [ + { "name": "from", "type": "Person" }, + { "name": "to", "type": "Person" }, + { "name": "contents", "type": "string" } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + } + ] } ``` @@ -292,19 +292,19 @@ A user operation details object containing: ```json { - "method": "eth_prepareUserOperation", - "params": [ - { - "to": "0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb", - "value": "0x0", - "data": "0x" - }, - { - "to": "0x660265edc169bab511a40c0e049cc1e33774443d", - "value": "0x0", - "data": "0x619a309f" - } - ] + "method": "eth_prepareUserOperation", + "params": [ + { + "to": "0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb", + "value": "0x0", + "data": "0x" + }, + { + "to": "0x660265edc169bab511a40c0e049cc1e33774443d", + "value": "0x0", + "data": "0x619a309f" + } + ] } ``` @@ -313,17 +313,17 @@ A user operation details object containing: ```json { - "callData": "0x70641a22000000000000000000000000f3de3c0d654fda23dad170f0f320a921725091270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e49871efa4000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000067fd192000000000000000000000000000000000000000001411a0c3b763237f484fdd70000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000280000000000000003b6d03400d4a11d5eeaac28ec3f61d100daf4d40471f185280000000000000003b6d03408f1b19622a888c53c8ee4f7d7b4dc8f574ff906800000000000000000000000000000000000000000000000000000000", - "initCode": "0x22ff1dc5998258faa1ea45a776b57484f8ab80a2296601cd0000000000000000000000005147ce3947a407c95687131be01a2b8d55fd0a400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000007d91ea6a0bc4a4238cd72386d935e35e3d8c318400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x1", - "gasLimits": { - "callGasLimit": "0x58a83", - "verificationGasLimit": "0xe8c4", - "preVerificationGas": "0xc57c" - }, - "dummySignature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "dummyPaymasterAndData": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "bundlerUrl": "https://bundler.example.com/rpc" + "callData": "0x70641a22000000000000000000000000f3de3c0d654fda23dad170f0f320a921725091270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e49871efa4000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000067fd192000000000000000000000000000000000000000001411a0c3b763237f484fdd70000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000280000000000000003b6d03400d4a11d5eeaac28ec3f61d100daf4d40471f185280000000000000003b6d03408f1b19622a888c53c8ee4f7d7b4dc8f574ff906800000000000000000000000000000000000000000000000000000000", + "initCode": "0x22ff1dc5998258faa1ea45a776b57484f8ab80a2296601cd0000000000000000000000005147ce3947a407c95687131be01a2b8d55fd0a400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000007d91ea6a0bc4a4238cd72386d935e35e3d8c318400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x1", + "gasLimits": { + "callGasLimit": "0x58a83", + "verificationGasLimit": "0xe8c4", + "preVerificationGas": "0xc57c" + }, + "dummySignature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "dummyPaymasterAndData": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "bundlerUrl": "https://bundler.example.com/rpc" } ``` @@ -374,22 +374,22 @@ A partial user operation object containing: ```json { - "method": "eth_patchUserOperation", - "params": [ - { - "sender": "0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4", - "nonce": "0x1", - "initCode": "0x", - "callData": "0x70641a22000000000000000000000000f3de3c0d654fda23dad170f0f320a921725091270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e49871efa4000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000067fd192000000000000000000000000000000000000000001411a0c3b763237f484fdd70000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000280000000000000003b6d03400d4a11d5eeaac28ec3f61d100daf4d40471f185280000000000000003b6d03408f1b19622a888c53c8ee4f7d7b4dc8f574ff906800000000000000000000000000000000000000000000000000000000", - "callGasLimit": "0x58a83", - "verificationGasLimit": "0xe8c4", - "preVerificationGas": "0xc57c", - "maxFeePerGas": "0x87f0878c0", - "maxPriorityFeePerGas": "0x1dcd6500", - "paymasterAndData": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } - ] + "method": "eth_patchUserOperation", + "params": [ + { + "sender": "0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4", + "nonce": "0x1", + "initCode": "0x", + "callData": "0x70641a22000000000000000000000000f3de3c0d654fda23dad170f0f320a921725091270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e49871efa4000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000067fd192000000000000000000000000000000000000000001411a0c3b763237f484fdd70000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000280000000000000003b6d03400d4a11d5eeaac28ec3f61d100daf4d40471f185280000000000000003b6d03408f1b19622a888c53c8ee4f7d7b4dc8f574ff906800000000000000000000000000000000000000000000000000000000", + "callGasLimit": "0x58a83", + "verificationGasLimit": "0xe8c4", + "preVerificationGas": "0xc57c", + "maxFeePerGas": "0x87f0878c0", + "maxPriorityFeePerGas": "0x1dcd6500", + "paymasterAndData": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + ] } ``` @@ -398,10 +398,10 @@ A partial user operation object containing: ```json { - "paymasterAndData": "0x952514d7cBCB495EACeB86e02154921401dB0Cd9dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000779b3fbb00000000000000006565b267000000000000000000000000000000000000000029195b31a9b1c6ccdeff53e359ebbcd5f075a93c1aaed93302e5fde5faf8047028b296b8a3fa4e22b063af5069ae9f656736ffda0ee090c0311155722b905f781b", - "callGasLimit": "0x58a83", - "verificationGasLimit": "0xe8c4", - "preVerificationGas": "0xc57c" + "paymasterAndData": "0x952514d7cBCB495EACeB86e02154921401dB0Cd9dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000779b3fbb00000000000000006565b267000000000000000000000000000000000000000029195b31a9b1c6ccdeff53e359ebbcd5f075a93c1aaed93302e5fde5faf8047028b296b8a3fa4e22b063af5069ae9f656736ffda0ee090c0311155722b905f781b", + "callGasLimit": "0x58a83", + "verificationGasLimit": "0xe8c4", + "preVerificationGas": "0xc57c" } ``` @@ -446,23 +446,23 @@ Signature: `string` - Hex-encoded signature. ```json { - "method": "eth_signUserOperation", - "params": [ - { - "sender": "0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4", - "nonce": "0x1", - "initCode": "0x", - "callData": "0x70641a22000000000000000000000000f3de3c0d654fda23dad170f0f320a921725091270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e49871efa4000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000067fd192000000000000000000000000000000000000000001411a0c3b763237f484fdd70000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000280000000000000003b6d03400d4a11d5eeaac28ec3f61d100daf4d40471f185280000000000000003b6d03408f1b19622a888c53c8ee4f7d7b4dc8f574ff906800000000000000000000000000000000000000000000000000000000", - "callGasLimit": "0x58a83", - "verificationGasLimit": "0xe8c4", - "preVerificationGas": "0xc57c", - "maxFeePerGas": "0x87f0878c0", - "maxPriorityFeePerGas": "0x1dcd6500", - "paymasterAndData": "0x952514d7cBCB495EACeB86e02154921401dB0Cd9dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000779b3fbb00000000000000006565b267000000000000000000000000000000000000000029195b31a9b1c6ccdeff53e359ebbcd5f075a93c1aaed93302e5fde5faf8047028b296b8a3fa4e22b063af5069ae9f656736ffda0ee090c0311155722b905f781b", - "signature": "0x" - }, - "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - ] + "method": "eth_signUserOperation", + "params": [ + { + "sender": "0x4584d2B4905087A100420AFfCe1b2d73fC69B8E4", + "nonce": "0x1", + "initCode": "0x", + "callData": "0x70641a22000000000000000000000000f3de3c0d654fda23dad170f0f320a921725091270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e49871efa4000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000067fd192000000000000000000000000000000000000000001411a0c3b763237f484fdd70000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000280000000000000003b6d03400d4a11d5eeaac28ec3f61d100daf4d40471f185280000000000000003b6d03408f1b19622a888c53c8ee4f7d7b4dc8f574ff906800000000000000000000000000000000000000000000000000000000", + "callGasLimit": "0x58a83", + "verificationGasLimit": "0xe8c4", + "preVerificationGas": "0xc57c", + "maxFeePerGas": "0x87f0878c0", + "maxPriorityFeePerGas": "0x1dcd6500", + "paymasterAndData": "0x952514d7cBCB495EACeB86e02154921401dB0Cd9dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000779b3fbb00000000000000006565b267000000000000000000000000000000000000000029195b31a9b1c6ccdeff53e359ebbcd5f075a93c1aaed93302e5fde5faf8047028b296b8a3fa4e22b063af5069ae9f656736ffda0ee090c0311155722b905f781b", + "signature": "0x" + }, + "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + ] } ``` diff --git a/snaps/reference/permissions.md b/snaps/reference/permissions.md index 3dce9ec5e1b..a3fed721897 100644 --- a/snaps/reference/permissions.md +++ b/snaps/reference/permissions.md @@ -18,7 +18,7 @@ manifest file: ```json title="snap.manifest.json" "initialPermissions": { - "snap_dialog": {} + "snap_dialog": {} } ``` @@ -45,28 +45,28 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:cronjob": { - "jobs": [ - { - "expression": "* * * * *", - "request": { - "method": "exampleMethodOne", - "params": { - "param1": "foo" - } - } - }, - { - "expression": "*/2 * * * *", - "request": { - "method": "exampleMethodTwo", - "params": { - "param1": "bar" - } - } - } - ] - } + "endowment:cronjob": { + "jobs": [ + { + "expression": "* * * * *", + "request": { + "method": "exampleMethodOne", + "params": { + "param1": "foo" + } + } + }, + { + "expression": "*/2 * * * *", + "request": { + "method": "exampleMethodTwo", + "params": { + "param1": "bar" + } + } + } + ] + } } ``` @@ -81,7 +81,7 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:ethereum-provider": {} + "endowment:ethereum-provider": {} } ``` @@ -101,7 +101,7 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:page-home": {} + "endowment:page-home": {} } ``` @@ -120,9 +120,9 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:keyring": { - "allowedOrigins": ["https://"] - } + "endowment:keyring": { + "allowedOrigins": ["https://"] + } } ``` @@ -143,7 +143,7 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:lifecycle-hooks": {} + "endowment:lifecycle-hooks": {} } ``` @@ -176,13 +176,13 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:name-lookup": { - "chains": ["eip155:1"], - "matchers": { - "tlds": ["crypto"], - "schemes": ["farcaster"] - } + "endowment:name-lookup": { + "chains": ["eip155:1"], + "matchers": { + "tlds": ["crypto"], + "schemes": ["farcaster"] } + } }, ``` @@ -205,7 +205,7 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:network-access": {} + "endowment:network-access": {} } ``` @@ -237,10 +237,10 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:rpc": { - "dapps": true, - "snaps": false - } + "endowment:rpc": { + "dapps": true, + "snaps": false + } } ``` @@ -253,13 +253,13 @@ Specify this caveat in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:rpc": { - "allowedOrigins": [ - "https://metamask.io", - "https://consensys.io", - "npm:@metamask/example-snap" - ] - } + "endowment:rpc": { + "allowedOrigins": [ + "https://metamask.io", + "https://consensys.io", + "npm:@metamask/example-snap" + ] + } } ``` @@ -288,9 +288,9 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:transaction-insight": { - "allowTransactionOrigin": true - } + "endowment:transaction-insight": { + "allowTransactionOrigin": true + } } ``` @@ -313,9 +313,9 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:signature-insight": { - "allowSignatureOrigin": true - } + "endowment:signature-insight": { + "allowSignatureOrigin": true + } }, ``` @@ -328,7 +328,7 @@ Specify this permission in the manifest file as follows: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:webassembly": {} + "endowment:webassembly": {} } ``` @@ -343,9 +343,9 @@ For example: ```json title="snap.manifest.json" "initialPermissions": { - "endowment:transaction-insight": { - "maxRequestTime": 10000 - } + "endowment:transaction-insight": { + "maxRequestTime": 10000 + } } ``` @@ -373,7 +373,7 @@ Calling `eth_requestAccounts` requires the ```json title="snap.manifest.json" "initialPermissions": { - "endowment:ethereum-provider": {} + "endowment:ethereum-provider": {} } ``` @@ -396,18 +396,18 @@ The following is an example `eth_accounts` permission: ```json { - "id": "47vm2UUi1pccNAeYKGmwF", - "parentCapability": "eth_accounts", - "invoker": "npm:SNAP_ID", - "caveats": [ - { - "type": "restrictReturnedAccounts", - "value": [ - "0xc403b37bf1e700cb214ea1be9de066824b420de6" - ] - } - ], - "date": 1692616452846 + "id": "47vm2UUi1pccNAeYKGmwF", + "parentCapability": "eth_accounts", + "invoker": "npm:SNAP_ID", + "caveats": [ + { + "type": "restrictReturnedAccounts", + "value": [ + "0xc403b37bf1e700cb214ea1be9de066824b420de6" + ] + } + ], + "date": 1692616452846 } ``` diff --git a/snaps/reference/snaps-api.md b/snaps/reference/snaps-api.md index d51f6d86243..1b3b27e80e3 100644 --- a/snaps/reference/snaps-api.md +++ b/snaps/reference/snaps-api.md @@ -41,14 +41,14 @@ An object containing the contents of the alert dialog: import { panel, text, heading } from "@metamask/snaps-sdk"; await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - heading("Something happened in the system"), - text("The thing that happened is..."), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + heading("Something happened in the system"), + text("The thing that happened is..."), + ]), + }, }); // Code that should execute after the alert has been acknowledged. @@ -77,18 +77,18 @@ An object containing the contents of the confirmation dialog: import { panel, text, heading } from "@metamask/snaps-sdk"; const result = await snap.request({ - method: "snap_dialog", - params: { - type: "confirmation", - content: panel([ - heading("Would you like to take the action?"), - text("The action is..."), - ]), - }, + method: "snap_dialog", + params: { + type: "confirmation", + content: panel([ + heading("Would you like to take the action?"), + text("The action is..."), + ]), + }, }); if (result === true) { - // Do the action. + // Do the action. } ``` @@ -116,15 +116,15 @@ The text entered by the user if the prompt was submitted or `null` if the prompt import { panel, text, heading } from "@metamask/snaps-sdk"; const walletAddress = await snap.request({ - method: "snap_dialog", - params: { - type: "prompt", - content: panel([ - heading("What is the wallet address?"), - text("Please enter the wallet address to be monitored"), - ]), - placeholder: "0x123...", - }, + method: "snap_dialog", + params: { + type: "prompt", + content: panel([ + heading("What is the wallet address?"), + text("Please enter the wallet address to be monitored"), + ]), + placeholder: "0x123...", + }, }); // walletAddress will be a string containing the address entered by the user. @@ -179,12 +179,12 @@ its corresponding key material: ```json title="snap.manifest.json" "initialPermissions": { - "snap_getBip32Entropy": [ - { - "path": ["m", "44'", "3'"], - "curve": "secp256k1" // Or "ed25519" - } - ] + "snap_getBip32Entropy": [ + { + "path": ["m", "44'", "3'"], + "curve": "secp256k1" // Or "ed25519" + } + ] } ``` @@ -196,12 +196,12 @@ import { SLIP10Node } from "@metamask/key-tree"; // This example uses Dogecoin, which has a derivation path starting with m/44'/3'. const dogecoinNode = await snap.request({ - method: "snap_getBip32Entropy", - params: { - // The path and curve must be specified in the initial permissions. - path: ["m", "44'", "3'"], - curve: "secp256k1", - }, + method: "snap_getBip32Entropy", + params: { + // The path and curve must be specified in the initial permissions. + path: ["m", "44'", "3'"], + curve: "secp256k1", + }, }); // Next, create an instance of a SLIP-10 node for the Dogecoin node. @@ -248,12 +248,12 @@ The public key as hexadecimal string. ```json title="snap.manifest.json" "initialPermissions": { - "snap_getBip32PublicKey": [ - { - "path": ["m", "44'", "3'", "0'", "0", "0"], - "curve": "secp256k1" - } - ] + "snap_getBip32PublicKey": [ + { + "path": ["m", "44'", "3'", "0'", "0", "0"], + "curve": "secp256k1" + } + ] } ``` @@ -263,13 +263,13 @@ The public key as hexadecimal string. ```javascript title="index.js" // This example uses Dogecoin, which has a derivation path starting with m/44'/3'. const dogecoinPublicKey = await snap.request({ - method: "snap_getBip32PublicKey", - params: { - // The path and curve must be specified in the initial permissions. - path: ["m", "44'", "3'", "0'", "0", "0"], - curve: "secp256k1", - compressed: false, - }, + method: "snap_getBip32PublicKey", + params: { + // The path and curve must be specified in the initial permissions. + path: ["m", "44'", "3'", "0'", "0", "0"], + curve: "secp256k1", + compressed: false, + }, }); // "0x..." @@ -333,11 +333,11 @@ and containing its corresponding key material: ```json title="snap.manifest.json" "initialPermissions": { - "snap_getBip44Entropy": [ - { - "coinType": 3 - } - ] + "snap_getBip44Entropy": [ + { + "coinType": 3 + } + ] } ``` @@ -349,10 +349,10 @@ import { getBIP44AddressKeyDeriver } from "@metamask/key-tree"; // This example uses Dogecoin, which has coin_type 3. const dogecoinNode = await snap.request({ - method: "snap_getBip44Entropy", - params: { - coinType: 3, - }, + method: "snap_getBip44Entropy", + params: { + coinType: 3, + }, }); // Next, create an address key deriver function for the Dogecoin coin_type node. @@ -393,20 +393,20 @@ import type { OnCronjobHandler } from "@metamask/snaps-sdk"; import { MethodNotFoundError } from "@metamask/snaps-sdk"; export const onCronjob: OnCronjobHandler = async ({ request }) => { - switch (request.method) { - case "execute": - // Find out if MetaMask is locked. - const { locked } = await snap.request({ - method: "snap_getClientStatus" - }); - - if (!locked) { - // Do something that requires MetaMask to be unlocked, such as access encrypted state. - } - - default: - throw new MethodNotFoundError(); - } + switch (request.method) { + case "execute": + // Find out if MetaMask is locked. + const { locked } = await snap.request({ + method: "snap_getClientStatus" + }); + + if (!locked) { + // Do something that requires MetaMask to be unlocked, such as access encrypted state. + } + + default: + throw new MethodNotFoundError(); + } }; ``` @@ -442,7 +442,7 @@ The entropy as a hexadecimal string. ```json title="snap.manifest.json" "initialPermissions": { - "snap_getEntropy": {} + "snap_getEntropy": {} } ``` @@ -451,11 +451,11 @@ The entropy as a hexadecimal string. ```javascript title="index.js" const entropy = await snap.request({ - method: "snap_getEntropy", - params: { - version: 1, - salt: "foo", // Optional - }, + method: "snap_getEntropy", + params: { + version: 1, + salt: "foo", // Optional. + }, }); // "0x..." @@ -488,13 +488,13 @@ The file content as a string in the requested encoding. ```json title="snap.manifest.json" "source": { - "shasum": "xxx", - "location": { - // ... - }, - "files": [ - "./files/myfile.bin" - ] + "shasum": "xxx", + "location": { + // ... + }, + "files": [ + "./files/myfile.bin" + ] } ``` @@ -503,11 +503,11 @@ The file content as a string in the requested encoding. ```javascript title="index.js" const contents = await snap.request({ - method: "snap_getFile", - params: { - path: "./files/myfile.bin", - encoding: "hex", - }, + method: "snap_getFile", + params: { + path: "./files/myfile.bin", + encoding: "hex", + }, }); // "0x..." @@ -534,17 +534,17 @@ const locale = await snap.request({ method: "snap_getLocale" }); let greeting = "Hello"; if(locale === "es") { - greeting = "Hola"; + greeting = "Hola"; } await snap.request({ - method: "snap_dialog", - params: { - type: "alert", - content: panel([ - text(greeting), - ]), - }, + method: "snap_dialog", + params: { + type: "alert", + content: panel([ + text(greeting), + ]), + }, }); ``` @@ -582,44 +582,44 @@ This can be done using [`snap_manageState`](#snap_managestate). import { Keyring, KeyringAccount } from "@metamask/keyring-api"; class MyKeyring implements Keyring { - // Other methods. - - async createAccount( - name: string, - options: Record | null = null, - ): Promise { - - const account: KeyringAccount = { - id: uuid(), - name, - options, - address, - supportedMethods: [ - "eth_sendTransaction", - "eth_sign", - "eth_signTransaction", - "eth_signTypedData_v1", - "eth_signTypedData_v2", - "eth_signTypedData_v3", - "eth_signTypedData_v4", - "eth_signTypedData", - "personal_sign", - ], - type: "eip155:eoa", - }; - - // Store the account in state. - - await snap.request({ - method: "snap_manageAccounts", - params: { - method: "createAccount", - params: { account }, - }, - }); - - return account; - } + // Other methods. + + async createAccount( + name: string, + options: Record | null = null, + ): Promise { + + const account: KeyringAccount = { + id: uuid(), + name, + options, + address, + supportedMethods: [ + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4", + "eth_signTypedData", + "personal_sign", + ], + type: "eip155:eoa", + }; + + // Store the account in state. + + await snap.request({ + method: "snap_manageAccounts", + params: { + method: "createAccount", + params: { account }, + }, + }); + + return account; + } } ``` @@ -646,19 +646,19 @@ This can be done using [`snap_manageState`](#snap_managestate). import { Keyring, KeyringAccount } from "@metamask/keyring-api"; class MyKeyring implements Keyring { - // Other methods. - - async updateAccount(account: KeyringAccount): Promise { - // Store the new account details in state. - - await snap.request({ - method: "snap_manageAccounts", - params: { - method: "updateAccount", - params: { account }, - }, - }); - } + // Other methods. + + async updateAccount(account: KeyringAccount): Promise { + // Store the new account details in state. + + await snap.request({ + method: "snap_manageAccounts", + params: { + method: "updateAccount", + params: { account }, + }, + }); + } } ``` @@ -685,19 +685,19 @@ This can be done using [`snap_manageState`](#snap_managestate). import { Keyring } from "@metamask/keyring-api"; class MyKeyring implements Keyring { - // Other methods. - - async deleteAccount(id: string): Promise { - // Delete the account from state. - - await snap.request({ - method: "snap_manageAccounts", - params: { - method: "deleteAccount", - params: { id }, - }, - }); - } + // Other methods. + + async deleteAccount(id: string): Promise { + // Delete the account from state. + + await snap.request({ + method: "snap_manageAccounts", + params: { + method: "deleteAccount", + params: { id }, + }, + }); + } } ``` @@ -718,21 +718,21 @@ An array of [account objects](keyring-api/account-management/objects.md#keyringa import { Keyring, KeyringAccount } from "@metamask/keyring-api"; class MyKeyring implements Keyring { - // Other methods. - - async checkIfAccountsInSync(): Promise { - - const knownAccounts: KeyringAccount[] = /* Grab accounts from Snap state. */; - - const listedAccounts: KeyringAccount[] = await snap.request({ - method: "snap_manageAccounts", - params: { - method: "listAccounts", - }, - }); - - // Compare the arrays and return the response. - } + // Other methods. + + async checkIfAccountsInSync(): Promise { + + const knownAccounts: KeyringAccount[] = /* Grab accounts from Snap state. */; + + const listedAccounts: KeyringAccount[] = await snap.request({ + method: "snap_manageAccounts", + params: { + method: "listAccounts", + }, + }); + + // Compare the arrays and return the response. + } } ``` @@ -758,19 +758,19 @@ import { Keyring } from "@metamask/keyring-api"; import { Json } from "@metamask/utils"; class MyKeyring implements Keyring { - // Other methods. - - async approveRequest(id: string, result?: Json): Promise { - // Do any Snap-side logic to finish approving the request. - - await snap.request({ - method: "snap_manageAccounts", - params: { - method: "submitResponse", - params: { id, result }, - }, - }); - } + // Other methods. + + async approveRequest(id: string, result?: Json): Promise { + // Do any Snap-side logic to finish approving the request. + + await snap.request({ + method: "snap_manageAccounts", + params: { + method: "submitResponse", + params: { id, result }, + }, + }); + } } ``` @@ -809,17 +809,17 @@ The value stored in state if the operation is `get`, and `null` otherwise. ```javascript title="index.js" // Persist some data. await snap.request({ - method: "snap_manageState", - params: { - operation: "update", - newState: { hello: "world" }, - }, + method: "snap_manageState", + params: { + operation: "update", + newState: { hello: "world" }, + }, }); // At a later time, get the data stored. const persistedData = await snap.request({ - method: "snap_manageState", - params: { operation: "get" }, + method: "snap_manageState", + params: { operation: "get" }, }); console.log(persistedData); @@ -827,10 +827,10 @@ console.log(persistedData); // If there's no need to store data anymore, clear it out. await snap.request({ - method: "snap_manageState", - params: { - operation: "clear", - }, + method: "snap_manageState", + params: { + operation: "clear", + }, }); ``` @@ -861,11 +861,11 @@ An object containing the contents of the notification: ```javascript title="index.js" await snap.request({ - method: "snap_notify", - params: { - type: "inApp", - message: "Hello, world!", - }, + method: "snap_notify", + params: { + type: "inApp", + message: "Hello, world!", + }, }); ``` @@ -896,24 +896,24 @@ The interface's ID to be used in [`snap_dialog`](#snap_dialog), returned from ```js title="index.js" const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: panel([ - heading("Interactive interface"), - button({ - value: "Click me", - name: "interactive-button", - }), - ]) - }, + method: "snap_createInterface", + params: { + ui: panel([ + heading("Interactive interface"), + button({ + value: "Click me", + name: "interactive-button", + }), + ]) + }, }); await snap.request({ - method: "snap_dialog", - params: { - type: "Alert", - id: interfaceId - } + method: "snap_dialog", + params: { + type: "Alert", + id: interfaceId + } }); ``` @@ -941,45 +941,45 @@ An object where each top-level property can be one of the following: ```js title="index.js" const interfaceId = await snap.request({ - method: "snap_createInterface", - params: { - ui: panel([ - heading("Interactive UI Example Snap"), - // A top-level input. - input({ - name: "top-level-input", - placeholder: "Enter something", - }), - // A top-level form... - form({ - name: "example-form", - children: [ - // ...with a nested input. - input({ - name: "nested-input", - placeholder: "Enter something", - }), - button("Submit", ButtonType.Submit, "submit"), - ], - }), - ]), - }, + method: "snap_createInterface", + params: { + ui: panel([ + heading("Interactive UI Example Snap"), + // A top-level input. + input({ + name: "top-level-input", + placeholder: "Enter something", + }), + // A top-level form... + form({ + name: "example-form", + children: [ + // ...with a nested input. + input({ + name: "nested-input", + placeholder: "Enter something", + }), + button("Submit", ButtonType.Submit, "submit"), + ], + }), + ]), + }, }); const state = await snap.request({ - method: "snap_getInterfaceState", - params: { - id: interfaceId, - }, + method: "snap_getInterfaceState", + params: { + id: interfaceId, + }, }); console.log(state); /* { - "top-level-input": "What the user typed in that field", - "example-form": { - "nested-input": "What the user typed in that field" - } + "top-level-input": "What the user typed in that field", + "example-form": { + "nested-input": "What the user typed in that field" + } } */ ``` @@ -1004,16 +1004,16 @@ An object containing: ```js title="index.js" export function onUserInput({ id, event }) { - console.log("Received input event", event); - - await snap.request({ - method: "snap_updateInterface", - params: { - id, - ui: panel([ - heading("New interface"), - ]), - }, - }); + console.log("Received input event", event); + + await snap.request({ + method: "snap_updateInterface", + params: { + id, + ui: panel([ + heading("New interface"), + ]), + }, + }); }; ``` diff --git a/wallet/concepts/wallet-interoperability.md b/wallet/concepts/wallet-interoperability.md index 75238c78c1a..13f364e9945 100644 --- a/wallet/concepts/wallet-interoperability.md +++ b/wallet/concepts/wallet-interoperability.md @@ -62,8 +62,8 @@ interface announces an event dispatched by the wallet: ```typescript interface EIP6963AnnounceProviderEvent extends CustomEvent { - type: "eip6963:announceProvider"; - detail: EIP6963ProviderDetail; + type: "eip6963:announceProvider"; + detail: EIP6963ProviderDetail; } ``` @@ -72,7 +72,7 @@ interface requests an event dispatched by a dapp: ```typescript interface EIP6963RequestProviderEvent extends Event { - type: "eip6963:requestProvider"; + type: "eip6963:requestProvider"; } ``` diff --git a/wallet/how-to/connect/detect-metamask.md b/wallet/how-to/connect/detect-metamask.md index 63d74fca16d..84ec5e2e7d2 100644 --- a/wallet/how-to/connect/detect-metamask.md +++ b/wallet/how-to/connect/detect-metamask.md @@ -23,7 +23,7 @@ code snippet into your browser's developer console: ```javascript if (typeof window.ethereum !== "undefined") { - console.log("MetaMask is installed!"); + console.log("MetaMask is installed!"); } ``` @@ -53,19 +53,19 @@ import detectEthereumProvider from "@metamask/detect-provider"; const provider = await detectEthereumProvider(); if (provider) { - // From now on, this should always be true: - // provider === window.ethereum - startApp(provider); // Initialize your dapp. + // From now on, this should always be true: + // provider === window.ethereum + startApp(provider); // Initialize your dapp. } else { - console.log("Please install MetaMask!"); + console.log("Please install MetaMask!"); } function startApp(provider) { - // If the provider returned by detectEthereumProvider isn't the same as window.ethereum, something - // is overwriting it – perhaps another wallet. See the "Connect to MetaMask" guide for detecting - // and connecting to multiple wallets. - if (provider !== window.ethereum) { - console.error("Do you have multiple wallets installed?"); - } - // Access the decentralized web! + // If the provider returned by detectEthereumProvider isn't the same as window.ethereum, something + // is overwriting it – perhaps another wallet. See the "Connect to MetaMask" guide for detecting + // and connecting to multiple wallets. + if (provider !== window.ethereum) { + console.error("Do you have multiple wallets installed?"); + } + // Access the decentralized web! } \ No newline at end of file diff --git a/wallet/how-to/connect/index.md b/wallet/how-to/connect/index.md index d3f1ee10ae2..f27a66665c1 100644 --- a/wallet/how-to/connect/index.md +++ b/wallet/how-to/connect/index.md @@ -57,31 +57,31 @@ In your Vite project, update `src/vite-env.d.ts` with the /// interface EIP6963ProviderInfo { - rdns: string - uuid: string - name: string - icon: string + rdns: string + uuid: string + name: string + icon: string } interface EIP6963ProviderDetail { - info: EIP6963ProviderInfo - provider: EIP1193Provider + info: EIP6963ProviderInfo + provider: EIP1193Provider } type EIP6963AnnounceProviderEvent = { - detail: { - info: EIP6963ProviderInfo, - provider: Readonly, - } + detail: { + info: EIP6963ProviderInfo, + provider: Readonly, + } } interface EIP1193Provider { - isStatus?: boolean - host?: string - path?: string - sendAsync?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void - send?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void - request: (request: { method: string, params?: Array }) => Promise + isStatus?: boolean + host?: string + path?: string + sendAsync?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + send?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + request: (request: { method: string, params?: Array }) => Promise } ``` @@ -101,9 +101,9 @@ import "./style.css" import { listProviders } from "./providers.ts" document.querySelector('#app')!.innerHTML = ` -
-
-
+
+
+
` listProviders(document.querySelector("#providerButtons")!) @@ -123,40 +123,40 @@ Create a file `src/providers.ts` with the following code: ```ts title="providers.ts" declare global { - interface WindowEventMap { - "eip6963:announceProvider": CustomEvent - } + interface WindowEventMap { + "eip6963:announceProvider": CustomEvent + } } // Connect to the selected provider using eth_requestAccounts. const connectWithProvider = async (wallet: EIP6963AnnounceProviderEvent["detail"]) => { - try { - await wallet.provider - .request({ method: "eth_requestAccounts" }) - } catch (error) { - console.error("Failed to connect to provider:", error) - } + try { + await wallet.provider + .request({ method: "eth_requestAccounts" }) + } catch (error) { + console.error("Failed to connect to provider:", error) + } } // Display detected providers as connect buttons. export function listProviders(element: HTMLDivElement) { - window.addEventListener("eip6963:announceProvider", - (event: EIP6963AnnounceProviderEvent) => { - const button = document.createElement("button") - - button.innerHTML = ` - ${event.detail.info.name} -
${event.detail.info.name}
- ` - - // Call connectWithProvider when a user selects the button. - button.onclick = () => connectWithProvider(event.detail) - element.appendChild(button) - } - ) + window.addEventListener("eip6963:announceProvider", + (event: EIP6963AnnounceProviderEvent) => { + const button = document.createElement("button") + + button.innerHTML = ` + ${event.detail.info.name} +
${event.detail.info.name}
+ ` + + // Call connectWithProvider when a user selects the button. + button.onclick = () => connectWithProvider(event.detail) + element.appendChild(button) + } + ) - // Notify event listeners and other parts of the dapp that a provider is requested. - window.dispatchEvent(new Event("eip6963:requestProvider")) + // Notify event listeners and other parts of the dapp that a provider is requested. + window.dispatchEvent(new Event("eip6963:requestProvider")) } ``` @@ -203,31 +203,31 @@ In your Vite project, update `src/vite-env.d.ts` with the /// interface EIP6963ProviderInfo { - rdns: string - uuid: string - name: string - icon: string + rdns: string + uuid: string + name: string + icon: string } interface EIP6963ProviderDetail { - info: EIP6963ProviderInfo - provider: EIP1193Provider + info: EIP6963ProviderInfo + provider: EIP1193Provider } type EIP6963AnnounceProviderEvent = { - detail: { - info: EIP6963ProviderInfo, - provider: Readonly, - } + detail: { + info: EIP6963ProviderInfo, + provider: Readonly, + } } interface EIP1193Provider { - isStatus?: boolean - host?: string - path?: string - sendAsync?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void - send?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void - request: (request: { method: string, params?: Array }) => Promise + isStatus?: boolean + host?: string + path?: string + sendAsync?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + send?: (request: { method: string, params?: Array }, callback: (error: Error | null, response: unknown) => void) => void + request: (request: { method: string, params?: Array }) => Promise } ``` @@ -247,9 +247,9 @@ import "./App.css" import { DiscoverWalletProviders } from "./components/DiscoverWalletProviders" function App() { - return ( - - ) + return ( + + ) } export default App @@ -269,54 +269,54 @@ import { useSyncProviders } from "../hooks/useSyncProviders" import { formatAddress } from "~/utils" export const DiscoverWalletProviders = () => { - const [selectedWallet, setSelectedWallet] = useState() - const [userAccount, setUserAccount] = useState("") - const providers = useSyncProviders() - - // Connect to the selected provider using eth_requestAccounts. - const handleConnect = async (providerWithInfo: EIP6963ProviderDetail) => { - try { - const accounts = await providerWithInfo.provider.request({ - method: "eth_requestAccounts" - }) - - setSelectedWallet(providerWithInfo) - setUserAccount(accounts?.[0]) - } catch (error) { - console.error(error) - } - } + const [selectedWallet, setSelectedWallet] = useState() + const [userAccount, setUserAccount] = useState("") + const providers = useSyncProviders() - // Display detected providers as connect buttons. - return ( - <> -

Wallets Detected:

+ // Connect to the selected provider using eth_requestAccounts. + const handleConnect = async (providerWithInfo: EIP6963ProviderDetail) => { + try { + const accounts = await providerWithInfo.provider.request({ + method: "eth_requestAccounts" + }) + + setSelectedWallet(providerWithInfo) + setUserAccount(accounts?.[0]) + } catch (error) { + console.error(error) + } + } + + // Display detected providers as connect buttons. + return ( + <> +

Wallets Detected:

+
+ { + providers.length > 0 ? providers?.map((provider: EIP6963ProviderDetail) => ( + + )) :
- { - providers.length > 0 ? providers?.map((provider: EIP6963ProviderDetail) => ( - - )) : -
- No Announced Wallet Providers -
- } + No Announced Wallet Providers
-
-

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

- {userAccount && -
-
- {selectedWallet.info.name} -
{selectedWallet.info.name}
-
({formatAddress(userAccount)})
-
-
- } - - ) + } +
+
+

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

+ {userAccount && +
+
+ {selectedWallet.info.name} +
{selectedWallet.info.name}
+
({formatAddress(userAccount)})
+
+
+ } + + ) } ``` @@ -343,32 +343,32 @@ Create a `src/hooks` directory and add a `store.ts` file with the following code ```ts title="hooks/store.ts" declare global { - interface WindowEventMap { - "eip6963:announceProvider": CustomEvent - } + interface WindowEventMap { + "eip6963:announceProvider": CustomEvent + } } // An array to store the detected wallet providers. let providers: EIP6963ProviderDetail[] = [] export const store = { - value: ()=> providers, - subscribe: (callback: ()=> void) => { - function onAnnouncement(event: EIP6963AnnounceProviderEvent){ - if(providers.map(p => p.info.uuid).includes(event.detail.info.uuid)) return - providers = [...providers, event.detail] - callback() - } - - // Listen for eip6963:announceProvider and call onAnnouncement when the event is triggered. - window.addEventListener("eip6963:announceProvider", onAnnouncement) - - // Dispatch the event, which triggers the event listener in the MetaMask wallet. - window.dispatchEvent(new Event("eip6963:requestProvider")) - - // Return a function that removes the event listern. - return () => window.removeEventListener("eip6963:announceProvider", onAnnouncement) + value: ()=> providers, + subscribe: (callback: ()=> void) => { + function onAnnouncement(event: EIP6963AnnounceProviderEvent){ + if(providers.map(p => p.info.uuid).includes(event.detail.info.uuid)) return + providers = [...providers, event.detail] + callback() } + + // Listen for eip6963:announceProvider and call onAnnouncement when the event is triggered. + window.addEventListener("eip6963:announceProvider", onAnnouncement) + + // Dispatch the event, which triggers the event listener in the MetaMask wallet. + window.dispatchEvent(new Event("eip6963:requestProvider")) + + // Return a function that removes the event listern. + return () => window.removeEventListener("eip6963:announceProvider", onAnnouncement) + } } ``` @@ -390,18 +390,18 @@ Create a `src/utils` directory and add a file `index.ts` with the following code ```ts title="index.ts" export const formatBalance = (rawBalance: string) => { - const balance = (parseInt(rawBalance) / 1000000000000000000).toFixed(2) - return balance + const balance = (parseInt(rawBalance) / 1000000000000000000).toFixed(2) + return balance } export const formatChainAsNum = (chainIdHex: string) => { - const chainIdNum = parseInt(chainIdHex) - return chainIdNum + const chainIdNum = parseInt(chainIdHex) + return chainIdNum } export const formatAddress = (addr: string) => { - const upperAfterLastTwo = addr.slice(0,2) + addr.slice(2) - return `${upperAfterLastTwo.substring(0, 5)}...${upperAfterLastTwo.substring(39)}` + const upperAfterLastTwo = addr.slice(0,2) + addr.slice(2) + return `${upperAfterLastTwo.substring(0, 5)}...${upperAfterLastTwo.substring(39)}` } ``` diff --git a/wallet/how-to/display/icon.md b/wallet/how-to/display/icon.md index 3e2cc351a17..e871c2ce623 100644 --- a/wallet/how-to/display/icon.md +++ b/wallet/how-to/display/icon.md @@ -16,6 +16,6 @@ The tag's `href` attribute is used for assigning the dapp icon. ```html - + ``` diff --git a/wallet/how-to/display/tokens.md b/wallet/how-to/display/tokens.md index 9f176871173..f6af6d40e08 100644 --- a/wallet/how-to/display/tokens.md +++ b/wallet/how-to/display/tokens.md @@ -42,32 +42,32 @@ const tokenDecimals = 18; const tokenImage = "http://placekitten.com/200/300"; try { - // 'wasAdded' is a boolean. Like any RPC method, an error can be thrown. - const wasAdded = await provider // Or window.ethereum if you don't support EIP-6963. - .request({ - method: "wallet_watchAsset", - params: { - type: "ERC20", - options: { - // The address of the token. - address: tokenAddress, - // A ticker symbol or shorthand, up to 5 characters. - symbol: tokenSymbol, - // The number of decimals in the token. - decimals: tokenDecimals, - // A string URL of the token logo. - image: tokenImage, - }, - }, - }); - - if (wasAdded) { - console.log("Thanks for your interest!"); - } else { - console.log("Your loss!"); - } + // 'wasAdded' is a boolean. Like any RPC method, an error can be thrown. + const wasAdded = await provider // Or window.ethereum if you don't support EIP-6963. + .request({ + method: "wallet_watchAsset", + params: { + type: "ERC20", + options: { + // The address of the token. + address: tokenAddress, + // A ticker symbol or shorthand, up to 5 characters. + symbol: tokenSymbol, + // The number of decimals in the token. + decimals: tokenDecimals, + // A string URL of the token logo. + image: tokenImage, + }, + }, + }); + + if (wasAdded) { + console.log("Thanks for your interest!"); + } else { + console.log("Your loss!"); + } } catch (error) { - console.log(error); + console.log(error); } ``` @@ -112,29 +112,28 @@ To prompt users to add a single NFT, add something like the following to your pr ```javascript try { - // 'wasAdded' is a boolean. Like any RPC method, an error can be thrown. - const wasAdded = await provider // Or window.ethereum if you don't support EIP-6963. - .request({ - method: "wallet_watchAsset", - params: { - // or 'ERC1155' - type: "ERC721", - options: { - // The address of the token. - address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", - // ERC-721 or ERC-1155 token ID. - tokenId: "1", - }, - }, - }); - - if (wasAdded) { - console.log("User successfully added the token!"); - } else { - console.log("User did not add the token."); - } + // wasAdded is a boolean. Like any RPC method, an error can be thrown. + const wasAdded = await provider // Or window.ethereum if you don't support EIP-6963. + .request({ + method: "wallet_watchAsset", + params: { + type: "ERC721", // Or "ERC1155". + options: { + // The address of the token. + address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", + // ERC-721 or ERC-1155 token ID. + tokenId: "1", + }, + }, + }); + + if (wasAdded) { + console.log("User successfully added the token!"); + } else { + console.log("User did not add the token."); + } } catch (error) { - console.log(error); + console.log(error); } ``` @@ -146,25 +145,25 @@ For example: ```javascript provider // Or window.ethereum if you don't support EIP-6963. - .sendAsync([{ - method: "wallet_watchAsset", - params: { - type: 'ERC721', - options: { - address: contractAddress, - tokenId: 1, - }, - } - }, { - method: "wallet_watchAsset", - params: { - type: 'ERC721', - options: { - address: contractAddress, - tokenId: 2, - }, - }, + .sendAsync([{ + method: "wallet_watchAsset", + params: { + type: "ERC721", + options: { + address: contractAddress, + tokenId: 1, + }, + } + }, { + method: "wallet_watchAsset", + params: { + type: "ERC721", + options: { + address: contractAddress, + tokenId: 2, + }, }, - ... - ]) + }, + ... + ]) ``` diff --git a/wallet/how-to/manage-networks/add-network.md b/wallet/how-to/manage-networks/add-network.md index 6fe8876bf5e..22034f8d59b 100644 --- a/wallet/how-to/manage-networks/add-network.md +++ b/wallet/how-to/manage-networks/add-network.md @@ -37,30 +37,30 @@ prompt a user to add and switch to a new network: ```javascript try { - await provider // Or window.ethereum if you don't support EIP-6963. + await provider // Or window.ethereum if you don't support EIP-6963. + .request({ + method: "wallet_switchEthereumChain", + params: [{ chainId: "0xf00" }], + }); +} catch (switchError) { + // This error code indicates that the chain has not been added to MetaMask. + if (switchError.code === 4902) { + try { + await provider // Or window.ethereum if you don't support EIP-6963. .request({ - method: "wallet_switchEthereumChain", - params: [{ chainId: "0xf00" }], + method: "wallet_addEthereumChain", + params: [ + { + chainId: "0xf00", + chainName: "...", + rpcUrls: ["https://..."] /* ... */, + }, + ], }); -} catch (switchError) { - // This error code indicates that the chain has not been added to MetaMask. - if (switchError.code === 4902) { - try { - await provider // Or window.ethereum if you don't support EIP-6963. - .request({ - method: "wallet_addEthereumChain", - params: [ - { - chainId: "0xf00", - chainName: "...", - rpcUrls: ["https://..."] /* ... */, - }, - ], - }); - } catch (addError) { - // Handle "add" error. - } + } catch (addError) { + // Handle "add" error. } - // Handle other "switch" errors. + } + // Handle other "switch" errors. } ``` \ No newline at end of file diff --git a/wallet/how-to/manage-networks/detect-network.md b/wallet/how-to/manage-networks/detect-network.md index 5a322d3b1ac..c4654f6395e 100644 --- a/wallet/how-to/manage-networks/detect-network.md +++ b/wallet/how-to/manage-networks/detect-network.md @@ -17,14 +17,14 @@ For example, the following code detects a user's network and when the user chang ```javascript title="index.js" const chainId = await provider // Or window.ethereum if you don't support EIP-6963. - .request({ method: "eth_chainId" }); + .request({ method: "eth_chainId" }); provider // Or window.ethereum if you don't support EIP-6963. - .on("chainChanged", handleChainChanged); + .on("chainChanged", handleChainChanged); function handleChainChanged(chainId) { - // We recommend reloading the page, unless you must do otherwise. - window.location.reload(); + // We recommend reloading the page, unless you must do otherwise. + window.location.reload(); } ``` diff --git a/wallet/how-to/manage-permissions.md b/wallet/how-to/manage-permissions.md index 6df44cd208a..318281f7d22 100644 --- a/wallet/how-to/manage-permissions.md +++ b/wallet/how-to/manage-permissions.md @@ -44,27 +44,27 @@ The following example uses `wallet_requestPermissions` to request permission fro document.getElementById("requestPermissionsButton", requestPermissions); function requestPermissions() { - provider // Or window.ethereum if you don't support EIP-6963. - .request({ - method: "wallet_requestPermissions", - params: [{ eth_accounts: {} }], - }) - .then((permissions) => { - const accountsPermission = permissions.find( - (permission) => permission.parentCapability === "eth_accounts" - ); - if (accountsPermission) { - console.log("eth_accounts permission successfully requested!"); - } - }) - .catch((error) => { - if (error.code === 4001) { - // EIP-1193 userRejectedRequest error - console.log("Permissions needed to continue."); - } else { - console.error(error); - } - }); + provider // Or window.ethereum if you don't support EIP-6963. + .request({ + method: "wallet_requestPermissions", + params: [{ eth_accounts: {} }], + }) + .then((permissions) => { + const accountsPermission = permissions.find( + (permission) => permission.parentCapability === "eth_accounts" + ); + if (accountsPermission) { + console.log("eth_accounts permission successfully requested!"); + } + }) + .catch((error) => { + if (error.code === 4001) { + // EIP-1193 userRejectedRequest error + console.log("Permissions needed to continue."); + } else { + console.error(error); + } + }); } ``` @@ -74,12 +74,12 @@ The following example uses `wallet_revokePermissions` to revoke the dapp's permi ```javascript await provider // Or window.ethereum if you don't support EIP-6963. - .request({ - method: "wallet_revokePermissions", - params: [ - { - eth_accounts: {}, - }, - ], - }); + .request({ + method: "wallet_revokePermissions", + params: [ + { + eth_accounts: {}, + }, + ], + }); ``` \ No newline at end of file diff --git a/wallet/how-to/onboard-users.md b/wallet/how-to/onboard-users.md index aa6e897220a..264618b421d 100644 --- a/wallet/how-to/onboard-users.md +++ b/wallet/how-to/onboard-users.md @@ -73,64 +73,64 @@ const CONNECT_TEXT = "Connect"; const CONNECTED_TEXT = "Connected"; export function OnboardingButton() { - const [buttonText, setButtonText] = React.useState(ONBOARD_TEXT); - const [isDisabled, setDisabled] = React.useState(false); - const [accounts, setAccounts] = React.useState([]); - const onboarding = React.useRef(); - - React.useEffect(() => { - if (!onboarding.current) { - onboarding.current = new MetaMaskOnboarding(); - } - }, []); - - React.useEffect(() => { - if (MetaMaskOnboarding.isMetaMaskInstalled()) { - if (accounts.length > 0) { - setButtonText(CONNECTED_TEXT); - setDisabled(true); - onboarding.current.stopOnboarding(); - } else { - setButtonText(CONNECT_TEXT); - setDisabled(false); - } - } - }, [accounts]); - - React.useEffect(() => { - function handleNewAccounts(newAccounts) { - setAccounts(newAccounts); - } - if (MetaMaskOnboarding.isMetaMaskInstalled()) { - provider // Or window.ethereum if you don't support EIP-6963. - .request({ method: "eth_requestAccounts" }) - .then(handleNewAccounts); - provider // Or window.ethereum if you don't support EIP-6963. - .on("accountsChanged", handleNewAccounts); - return () => { - provider // Or window.ethereum if you don't support EIP-6963. - .removeListener( - "accountsChanged", - handleNewAccounts - ); - }; - } - }, []); - - const onClick = () => { - if (MetaMaskOnboarding.isMetaMaskInstalled()) { - provider // Or window.ethereum if you don't support EIP-6963. - .request({ method: "eth_requestAccounts" }) - .then((newAccounts) => setAccounts(newAccounts)); - } else { - onboarding.current.startOnboarding(); - } - }; - return ( - - ); + const [buttonText, setButtonText] = React.useState(ONBOARD_TEXT); + const [isDisabled, setDisabled] = React.useState(false); + const [accounts, setAccounts] = React.useState([]); + const onboarding = React.useRef(); + + React.useEffect(() => { + if (!onboarding.current) { + onboarding.current = new MetaMaskOnboarding(); + } + }, []); + + React.useEffect(() => { + if (MetaMaskOnboarding.isMetaMaskInstalled()) { + if (accounts.length > 0) { + setButtonText(CONNECTED_TEXT); + setDisabled(true); + onboarding.current.stopOnboarding(); + } else { + setButtonText(CONNECT_TEXT); + setDisabled(false); + } + } + }, [accounts]); + + React.useEffect(() => { + function handleNewAccounts(newAccounts) { + setAccounts(newAccounts); + } + if (MetaMaskOnboarding.isMetaMaskInstalled()) { + provider // Or window.ethereum if you don't support EIP-6963. + .request({ method: "eth_requestAccounts" }) + .then(handleNewAccounts); + provider // Or window.ethereum if you don't support EIP-6963. + .on("accountsChanged", handleNewAccounts); + return () => { + provider // Or window.ethereum if you don't support EIP-6963. + .removeListener( + "accountsChanged", + handleNewAccounts + ); + }; + } + }, []); + + const onClick = () => { + if (MetaMaskOnboarding.isMetaMaskInstalled()) { + provider // Or window.ethereum if you don't support EIP-6963. + .request({ method: "eth_requestAccounts" }) + .then((newAccounts) => setAccounts(newAccounts)); + } else { + onboarding.current.startOnboarding(); + } + }; + return ( + + ); } ``` diff --git a/wallet/how-to/run-devnet.md b/wallet/how-to/run-devnet.md index 5adab789b2a..e6d1e54c5fa 100644 --- a/wallet/how-to/run-devnet.md +++ b/wallet/how-to/run-devnet.md @@ -52,14 +52,14 @@ Follow these steps to connect MetaMask to Hardhat Network. ```js title="hardhat.config.js" module.exports = { - networks: { - hardhat: { - accounts: { - mnemonic: process.env.SEED_PHRASE, - }, - chainId: 1337, - }, + networks: { + hardhat: { + accounts: { + mnemonic: process.env.SEED_PHRASE, + }, + chainId: 1337, }, + }, }; ``` diff --git a/wallet/how-to/secure-dapp.md b/wallet/how-to/secure-dapp.md index 6ef7a9d2267..004c6e2674b 100644 --- a/wallet/how-to/secure-dapp.md +++ b/wallet/how-to/secure-dapp.md @@ -45,11 +45,11 @@ For example, in Express.js, add the following middleware at the top of your serv ```js app.use((req, res, next) => { - res.setHeader( - "Content-Security-Policy", - "default-src 'self'; frame-ancestors 'none'" - ); - next(); + res.setHeader( + "Content-Security-Policy", + "default-src 'self'; frame-ancestors 'none'" + ); + next(); }); ``` @@ -74,10 +74,10 @@ For example: ```html - + ``` @@ -86,7 +86,7 @@ For example: CSP configuration is specific to each dapp. We recommend starting with the following secure and restrictive CSP: -``` +```text default-src 'self'; frame-ancestors 'none' ``` @@ -99,7 +99,7 @@ From here, you can make adjustments as needed by your dapp to support the conten For example, if your dapp loads images hosted on [OpenSea](https://opensea.io/), you can enable this by adding `img-src 'opensea.io'` to your CSP: -``` +```text default-src: 'self'; frame-ancestors 'none'; img-src: 'opensea.io' ``` diff --git a/wallet/how-to/use-sdk/3rd-party-libraries/wagmi.md b/wallet/how-to/use-sdk/3rd-party-libraries/wagmi.md index 32036ca9b7c..7dea79d0208 100644 --- a/wallet/how-to/use-sdk/3rd-party-libraries/wagmi.md +++ b/wallet/how-to/use-sdk/3rd-party-libraries/wagmi.md @@ -34,18 +34,18 @@ import { mainnet, sepolia } from "wagmi/chains"; import { metaMask } from "wagmi/connectors"; export const config = createConfig({ - chains: [mainnet, sepolia], - connectors: [ - metaMask({ - dappMetadata: { - name: "Example Wagmi dapp", - }, - }), - ], - transports: { - [mainnet.id]: http(), - [sepolia.id]: http(), - }, + chains: [mainnet, sepolia], + connectors: [ + metaMask({ + dappMetadata: { + name: "Example Wagmi dapp", + }, + }), + ], + transports: { + [mainnet.id]: http(), + [sepolia.id]: http(), + }, }); ``` @@ -56,13 +56,13 @@ When configuring the connector, make sure to configure the proper ```javascript connectors: [ - metaMask({ - dappMetadata: { - name: "Example Wagmi dapp", - }, - infuraAPIKey: "YOUR-API-KEY", - // Other options - }), + metaMask({ + dappMetadata: { + name: "Example Wagmi dapp", + }, + infuraAPIKey: "YOUR-API-KEY", + // Other options. + }), ], ``` diff --git a/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard.md b/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard.md index faf1cd48c7c..8e9ab797577 100644 --- a/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard.md +++ b/wallet/how-to/use-sdk/3rd-party-libraries/web3-onboard.md @@ -46,12 +46,12 @@ example, [`dappMetadata`](../../../reference/sdk-js-options.md#dappmetadata): ```javascript const metamaskSDKWallet = metamaskSDK({ - options: { - extensionOnly: false, - dappMetadata: { - name: "Example Web3-Onboard Dapp", - }, + options: { + extensionOnly: false, + dappMetadata: { + name: "Example Web3-Onboard Dapp", }, + }, }); ``` @@ -61,11 +61,11 @@ Use the module as follows: ```javascript const onboard = Onboard({ - // Other Onboard options - wallets: [ - metamaskSDKWallet, - // Other wallets - ], + // Other Onboard options. + wallets: [ + metamaskSDKWallet, + // Other wallets. + ], }); const connectedWallets = await onboard.connectWallet(); diff --git a/wallet/how-to/use-sdk/gaming/unity/connect-and-sign.md b/wallet/how-to/use-sdk/gaming/unity/connect-and-sign.md index 1073d0822c4..7af278f9165 100644 --- a/wallet/how-to/use-sdk/gaming/unity/connect-and-sign.md +++ b/wallet/how-to/use-sdk/gaming/unity/connect-and-sign.md @@ -26,7 +26,7 @@ You can [connect and sign](../../javascript/connect-and-sign.md) in a single int ```csharp public void ConnectAndSign() { - MetaMaskUnity.Instance.ConnectAndSign("This is a test message"); + MetaMaskUnity.Instance.ConnectAndSign("This is a test message"); } ``` @@ -45,6 +45,6 @@ You can [connect and sign](../../javascript/connect-and-sign.md) in a single int ```csharp public void OnButtonClick() { - ConnectAndSign(); + ConnectAndSign(); } ``` diff --git a/wallet/how-to/use-sdk/gaming/unity/dweb.md b/wallet/how-to/use-sdk/gaming/unity/dweb.md index 13c09de4b7c..6da71a62ab9 100644 --- a/wallet/how-to/use-sdk/gaming/unity/dweb.md +++ b/wallet/how-to/use-sdk/gaming/unity/dweb.md @@ -28,7 +28,7 @@ This method initializes the wrapper with necessary configuration parameters, inc authentication details required to interact with the Decentraweb name resolver API. ```csharp -// Initialize the wrapper +// Initialize the wrapper. var apiWrapper = newDWebAPIWrapper(); ``` @@ -46,13 +46,13 @@ The name resolver processes the request and responds with the Ethereum address. ```csharp -// Initialize the wrapper +// Initialize the wrapper. var apiWrapper = newDWebAPIWrapper(); -// Get the user's human-readable name +// Get the user's human-readable name. var name = "user.dweb"; -// Resolve the name to an Ethereum address +// Resolve the name to an Ethereum address. var address = await apiWrapper.ResolveNameAsync(name); ``` @@ -61,8 +61,8 @@ var address = await apiWrapper.ResolveNameAsync(name); ```json { - "success": true, - "result": "0xcB3E45F337Dd3Beeba98F5F9F9A16e9cD152cC86" + "success": true, + "result": "0xcB3E45F337Dd3Beeba98F5F9F9A16e9cD152cC86" } ``` @@ -83,13 +83,13 @@ The SDK processes the request and responds with the human-readable name. ```csharp -// Initialize the wrapper +// Initialize the wrapper. var apiWrapper = newDWebAPIWrapper(); -// Get the user's address +// Get the user's address. var address = "0xcB3E45F337Dd3Beeba98F5F9F9A16e9cD152cC86" -// Resolve the address to a human-readable name +// Resolve the address to a human-readable name. var name = await apiWrapper.GetNameAsync(address) ``` @@ -98,11 +98,11 @@ var name = await apiWrapper.GetNameAsync(address) ```json { - "success": true, - "result": { - "name": "lordsats", - "confirmed": true - } + "success": true, + "result": { + "name": "lordsats", + "confirmed": true + } } ``` @@ -116,23 +116,23 @@ The following is an example of using the Unity SDK Decentraweb integration to cr ```csharp public async Task FormTransactionAsync() { - // Initialize the wrapper + // Initialize the wrapper. var apiWrapper = new DWebAPIWrapper(); - // Get the user's human-readable name + // Get the user's human-readable name. var name = "user.dweb"; - // Resolve the name to an Ethereum address + // Resolve the name to an Ethereum address. var address = await apiWrapper.ResolveNameAsync(name); - // Form the transaction + // Form the transaction. var transaction = new Transaction { - To = address, - Value = 1.0m, - Gas = 21000 + To = address, + Value = 1.0m, + Gas = 21000 }; - // The rest of the transaction formation code... + // The rest of the transaction formation code. } ``` diff --git a/wallet/how-to/use-sdk/gaming/unity/index.md b/wallet/how-to/use-sdk/gaming/unity/index.md index 4150089da39..e1983502793 100644 --- a/wallet/how-to/use-sdk/gaming/unity/index.md +++ b/wallet/how-to/use-sdk/gaming/unity/index.md @@ -61,15 +61,15 @@ If you don't have TextMeshPro installed, the Unity editor automatically prompts Unity SDK package structure

-| File or directory | Contents | -| ------------------------ | ---------------------------------------------- | -| `Documentation` | Documentation and link to online documentation | -| `Editor` | Editor-only code such as Setup GUI windows, data persistence for SDK settings | -| `Plugins` | Plugins needed by the package (the ECIES Platform runtime libraries and core SDK Codebase) | +| File or directory | Contents | +|--------------------------|----------------------------------------------------------------------------------------------------------------------------------| +| `Documentation` | Documentation and link to online documentation | +| `Editor` | Editor-only code such as Setup GUI windows, data persistence for SDK settings | +| `Plugins` | Plugins needed by the package (the ECIES Platform runtime libraries and core SDK Codebase) | | `Runtime` | Main scripts for the SDK that are environment-agnostic, including the C# scripts that provide the base implementation of the SDK | -| `Samples` | Test application scene that can be used as a referral for your project, including modal popups and dynamic UI scaling | -| `LICENSE.md` | Package license | -| `Third Party Notices.md` | Third party notices | +| `Samples` | Test application scene that can be used as a referral for your project, including modal popups and dynamic UI scaling | +| `LICENSE.md` | Package license | +| `Third Party Notices.md` | Third party notices |

@@ -117,7 +117,7 @@ once the wallet is connected: wallet.WalletConnected += OnWalletConnected; void OnWalletConnected(object sender, EventArgs e) { - Debug.Log("Wallet is connected"); + Debug.Log("Wallet is connected"); } ``` @@ -154,7 +154,7 @@ var wallet = MetaMaskUnity.Instance.Wallet; wallet.WalletAuthorized += OnWalletAuthorized; void OnWalletAuthorized(object sender, EventArgs e) { - Debug.Log("Wallet is authorized"); + Debug.Log("Wallet is authorized"); } ``` @@ -165,15 +165,15 @@ The following is a sample transaction request: var wallet = MetaMaskUnity.Instance.Wallet; var transactionParams = new MetaMaskTransaction { - To = "0xd0059fB234f15dFA9371a7B45c09d451a2dd2B5a", - From = MetaMaskUnity.Instance.Wallet.SelectedAddress, - Value = "0x0" + To = "0xd0059fB234f15dFA9371a7B45c09d451a2dd2B5a", + From = MetaMaskUnity.Instance.Wallet.SelectedAddress, + Value = "0x0" }; var request = new MetaMaskEthereumRequest { - Method = "eth_sendTransaction", - Parameters = new MetaMaskTransaction[] { transactionParams } + Method = "eth_sendTransaction", + Parameters = new MetaMaskTransaction[] { transactionParams } }; await wallet.Request(request); ``` diff --git a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-factory.md b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-factory.md index 6656b1b879f..c928d1c6742 100644 --- a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-factory.md +++ b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-factory.md @@ -38,11 +38,11 @@ The declared `class` must inherit from the given interface type `T`. [BackedType(typeof(ERC20Backing))] public interface ERC20 : IContract { - [EvmMethodInfo(Name = "decimals", View = true)] - [return: EvmParameterInfo(Type = "uint8")] - Task Decimals(); + [EvmMethodInfo(Name = "decimals", View = true)] + [return: EvmParameterInfo(Type = "uint8")] + Task Decimals(); - // TODO Define other interface methods + // Define other interface methods. } ``` @@ -55,20 +55,20 @@ invoke the correct logic for the given `method` and `args`. ```csharp public class ERC20Backing : Contract, ERC20 { - public string Address - { - get => base.Address; - } - - [EvmMethodInfo(Name = "decimals", View = true)] - [return: EvmParameterInfo(Type = "uint8")] - public Task Decimals() - { - var method = System.Reflection.MethodBase.GetCurrentMethod(); - return (Task) InvokeMethod(method, new object[] { }); - } - - // TODO Define other interface methods + public string Address + { + get => base.Address; + } + + [EvmMethodInfo(Name = "decimals", View = true)] + [return: EvmParameterInfo(Type = "uint8")] + public Task Decimals() + { + var method = System.Reflection.MethodBase.GetCurrentMethod(); + return (Task) InvokeMethod(method, new object[] { }); + } + + // Define other interface methods. } ``` diff --git a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-interface.md b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-interface.md index c4bea341c31..9cd9eaf27bc 100644 --- a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-interface.md +++ b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-interface.md @@ -24,7 +24,7 @@ Optionally, declare the [`BackedType` attribute](contract-factory.md#backed-type #endif public interface ERC20 : IContract { - // TODO Declare functions + // Declare functions. } ``` @@ -39,7 +39,7 @@ To declare a `view` or `pure` function of the contract, first set the return typ #endif public interface ERC20 : IContract { - Task BalanceOf(EvmAddress account); + Task BalanceOf(EvmAddress account); } ``` @@ -53,8 +53,8 @@ This includes the `Name` and whether it's a `View` function: #endif public interface ERC20 : IContract { - [EvmMethodInfo(Name = "balanceOf", View = true)] - Task BalanceOf(EvmAddress account); + [EvmMethodInfo(Name = "balanceOf", View = true)] + Task BalanceOf(EvmAddress account); } ``` @@ -68,8 +68,8 @@ types, such as `EvmAddress` to be `address` and `string` to be `string`. #endif public interface ERC20 : IContract { - [EvmMethodInfo(Name = "balanceOf", View = true)] - Task BalanceOf([EvmParameterInfo(Type = "address")] string account); + [EvmMethodInfo(Name = "balanceOf", View = true)] + Task BalanceOf([EvmParameterInfo(Type = "address")] string account); } ``` @@ -81,12 +81,12 @@ To define the EVM return type for the function, you can use `EvmParamterInfo` on #endif public interface ERC20 : IContract { - [EvmMethodInfo(Name = "balanceOf", View = true)] - Task BalanceOf(EvmAddress account); - - [EvmMethodInfo(Name = "decimals", View = true)] - [return: EvmParameterInfo(Type = "uint8")] - Task Decimals(); + [EvmMethodInfo(Name = "balanceOf", View = true)] + Task BalanceOf(EvmAddress account); + + [EvmMethodInfo(Name = "decimals", View = true)] + [return: EvmParameterInfo(Type = "uint8")] + Task Decimals(); } ``` @@ -116,17 +116,17 @@ Also, do one of the following: #endif public interface ERC20 : IContract { - public static readonly string Bytecode = "0x6080604052348015620000115760008...."; - - [EvmConstructorMethod] - Task DeployNew(String name_, String symbol_); - - [EvmMethodInfo(Name = "balanceOf", View = true)] - Task BalanceOf(EvmAddress account); + public static readonly string Bytecode = "0x6080604052348015620000115760008...."; - [EvmMethodInfo(Name = "decimals", View = true)] - [return: EvmParameterInfo(Type = "uint8")] - Task Decimals(); + [EvmConstructorMethod] + Task DeployNew(String name_, String symbol_); + + [EvmMethodInfo(Name = "balanceOf", View = true)] + Task BalanceOf(EvmAddress account); + + [EvmMethodInfo(Name = "decimals", View = true)] + [return: EvmParameterInfo(Type = "uint8")] + Task Decimals(); } ``` @@ -138,15 +138,15 @@ Also, do one of the following: #endif public interface ERC20 : IContract { - [EvmConstructorMethod(Bytecode = "0x608060405238....")] - Task DeployNew(String name_, String symbol_); - - [EvmMethodInfo(Name = "balanceOf", View = true)] - Task BalanceOf(EvmAddress account); - - [EvmMethodInfo(Name = "decimals", View = true)] - [return: EvmParameterInfo(Type = "uint8")] - Task Decimals(); + [EvmConstructorMethod(Bytecode = "0x608060405238....")] + Task DeployNew(String name_, String symbol_); + + [EvmMethodInfo(Name = "balanceOf", View = true)] + Task BalanceOf(EvmAddress account); + + [EvmMethodInfo(Name = "decimals", View = true)] + [return: EvmParameterInfo(Type = "uint8")] + Task Decimals(); } ``` diff --git a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-provider.md b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-provider.md index 55e03359ecd..4172750e54f 100644 --- a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-provider.md +++ b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/contract-provider.md @@ -28,10 +28,10 @@ It must decode the JSON-RPC result response into the type `TR`. The `IProvider` must also define two additional properties: ```csharp -// The current chain ID the provider is connected to +// The current chain ID the provider is connected to. long ChainId { get; } -// The current address connected to the provider +// The current address connected to the provider. string ConnectedAddress { get; } ``` @@ -46,7 +46,7 @@ To easily support this function, use `Request`: ```csharp public object Request(string method, object[] parameters = null) { - return this.Request(method, parameters); + return this.Request(method, parameters); } ``` @@ -77,9 +77,9 @@ The desired type is defined in the [contract interface](contract-interface.md) u The `ILegacyProvider` must also define two additional properties: ```csharp -// The current chain ID the provider is connected to +// The current chain ID the provider is connected to. long ChainId { get; } -// The current address connected to the provider +// The current address connected to the provider. string ConnectedAddress { get; } ``` diff --git a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/index.md b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/index.md index 0972dc232b8..9c20f80663b 100644 --- a/wallet/how-to/use-sdk/gaming/unity/smart-contracts/index.md +++ b/wallet/how-to/use-sdk/gaming/unity/smart-contracts/index.md @@ -58,10 +58,10 @@ The following is an example of using a contract: ```csharp public async void Start() { - var metaMask = MetaMaskUnity.Instance.Wallet; - var address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; - - ERC20 usdc = Contract.Attach(address, metaMask); + var metaMask = MetaMaskUnity.Instance.Wallet; + var address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; + + ERC20 usdc = Contract.Attach(address, metaMask); } ``` @@ -72,10 +72,10 @@ For example: ```csharp public async void Start() { - // ... setup ... + // Setup... - var balance = await usdc.BalanceOf(metaMask.SelectedAddress); - Debug.Log(balance); + var balance = await usdc.BalanceOf(metaMask.SelectedAddress); + Debug.Log(balance); } ``` diff --git a/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests.md b/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests.md index 54d3cba73c3..1ac3f8f83d8 100644 --- a/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests.md +++ b/wallet/how-to/use-sdk/javascript/batch-json-rpc-requests.md @@ -49,32 +49,32 @@ The following is an example of using `metamask_batch` to batch [`personal_sign`](/wallet/reference/personal_sign) and [`eth_sendTransaction`](/wallet/reference/eth_sendtransaction) in React, Next.js, or React Native/Expo: -```javascript +```javascript title="index.js" import { metamask_batch } from "metamask-sdk"; function MyComponent() { - const handleBatchRequest = async () => { - const batchRequests = [ - { method: "personal_sign", params: ["message", "address"] }, - { - method: "eth_sendTransaction", - params: [ - { - /* transaction parameters */ - }, - ], - }, - ]; - - try { - const results = await metamask_batch(batchRequests); - console.log(results); // Process results - } catch (error) { - console.error("Batch request failed", error); - } - }; - - return ; + const handleBatchRequest = async () => { + const batchRequests = [ + { method: "personal_sign", params: ["message", "address"] }, + { + method: "eth_sendTransaction", + params: [ + { + /* Transaction parameters */ + }, + ], + }, + ]; + + try { + const results = await metamask_batch(batchRequests); + console.log(results); // Process results. + } catch (error) { + console.error("Batch request failed", error); + } + }; + + return ; } ``` @@ -84,33 +84,33 @@ The following is an example of using `metamask_batch` to batch [`personal_sign`](/wallet/reference/personal_sign) and [`eth_sendTransaction`](/wallet/reference/eth_sendtransaction) in Vue.js: -```javascript +```javascript title="App.vue" ``` diff --git a/wallet/how-to/use-sdk/javascript/connect-and-sign.md b/wallet/how-to/use-sdk/javascript/connect-and-sign.md index 72c872c9ad5..7dcfb64c4e9 100644 --- a/wallet/how-to/use-sdk/javascript/connect-and-sign.md +++ b/wallet/how-to/use-sdk/javascript/connect-and-sign.md @@ -44,14 +44,14 @@ Use the `connectAndSign` method as follows: ```javascript const connectAndSign = async () => { - try { - const signResult = await sdk?.connectAndSign({ - msg: "Connect + Sign message", - }); - setResponse(signResult); - } catch (err) { - console.warn("failed to connect..", err); - } + try { + const signResult = await sdk?.connectAndSign({ + msg: "Connect + Sign message", + }); + setResponse(signResult); + } catch (err) { + console.warn("failed to connect..", err); + } }; ``` @@ -71,25 +71,25 @@ import React, { useState } from "react"; import { useSDK } from "@metamask/sdk-react"; function MyComponent() { - const { sdk } = useSDK(); - const [signedMessage, setSignedMessage] = useState(""); - - const handleConnectAndSign = async () => { - try { - const message = "Your message here"; - const signature = await sdk.connectAndSign({ msg: message }); - setSignedMessage(signature); - } catch (error) { - console.error("Error in signing:", error); - } - }; - - return ( -
- - {signedMessage &&

Signed Message: {signedMessage}

} -
- ); + const { sdk } = useSDK(); + const [signedMessage, setSignedMessage] = useState(""); + + const handleConnectAndSign = async () => { + try { + const message = "Your message here"; + const signature = await sdk.connectAndSign({ msg: message }); + setSignedMessage(signature); + } catch (error) { + console.error("Error in signing:", error); + } + }; + + return ( +
+ + {signedMessage &&

Signed Message: {signedMessage}

} +
+ ); } ``` diff --git a/wallet/how-to/use-sdk/javascript/display-custom-modals.md b/wallet/how-to/use-sdk/javascript/display-custom-modals.md index 865499c8dcf..2793a0f8087 100644 --- a/wallet/how-to/use-sdk/javascript/display-custom-modals.md +++ b/wallet/how-to/use-sdk/javascript/display-custom-modals.md @@ -26,13 +26,13 @@ This example uses the [MetaMask React SDK](react/index.md). Create a custom modal component that aligns with your dapp's design and functionality requirements. -```javascript +```javascript title="App.js" import React from "react"; const CustomModal = ({ onClose }) => ( -
- -
+
+ +
); export default CustomModal; @@ -45,48 +45,45 @@ use the [`modals`](../../../reference/sdk-js-options.md#modals) SDK option to se for scenarios such as when MetaMask isn't installed. For example: -```javascript +```javascript title="index.js" import { MetaMaskProvider } from "@metamask/sdk-react"; import CustomModal from "./CustomModal"; import ReactDOM from "react-dom"; const App = () => ( - { - let modalContainer = null; - - return { - mount: () => { - modalContainer = document.createElement("div"); - document.body.appendChild(modalContainer); - - ReactDOM.render( - { - ReactDOM.unmountComponentAtNode( - modalContainer - ); - modalContainer.remove(); - }} - />, - modalContainer - ); - }, - unmount: () => { - if (modalContainer) { - ReactDOM.unmountComponentAtNode(modalContainer); - modalContainer.remove(); - } - }, - }; - }, + { + let modalContainer = null; + + return { + mount: () => { + modalContainer = document.createElement("div"); + document.body.appendChild(modalContainer); + + ReactDOM.render( + { + ReactDOM.unmountComponentAtNode(modalContainer); + modalContainer.remove(); + }} + />, + modalContainer + ); }, - }} - > - {/* Other components */} - + unmount: () => { + if (modalContainer) { + ReactDOM.unmountComponentAtNode(modalContainer); + modalContainer.remove(); + } + }, + }; + }, + }, + }} + > + {/* Other components */} + ); export default App; diff --git a/wallet/how-to/use-sdk/javascript/index.md b/wallet/how-to/use-sdk/javascript/index.md index a46f65e5ad3..4cae2ada789 100644 --- a/wallet/how-to/use-sdk/javascript/index.md +++ b/wallet/how-to/use-sdk/javascript/index.md @@ -48,7 +48,7 @@ npm i @metamask/sdk In your project script, add the following to import the SDK: -```javascript +```javascript title="index.js" import { MetaMaskSDK } from "@metamask/sdk"; ``` @@ -56,17 +56,17 @@ import { MetaMaskSDK } from "@metamask/sdk"; Instantiate the SDK using any [options](../../../reference/sdk-js-options.md): -```javascript +```javascript title="index.js" const MMSDK = new MetaMaskSDK({ - dappMetadata: { - name: "JavaScript example dapp", - url: window.location.href, - }, - infuraAPIKey: process.env.INFURA_API_KEY, - // Other options + dappMetadata: { + name: "JavaScript example dapp", + url: window.location.href, + }, + infuraAPIKey: process.env.INFURA_API_KEY, + // Other options. }); -// You can also access via window.ethereum +// You can also access via window.ethereum. const ethereum = MMSDK.getProvider(); ``` @@ -99,15 +99,15 @@ You can copy the full JavaScript example to get started: import { MetaMaskSDK } from "@metamask/sdk"; const MMSDK = new MetaMaskSDK({ - dappMetadata: { - name: "Example JavaScript Dapp", - url: window.location.href, - }, - infuraAPIKey: process.env.INFURA_API_KEY, - // Other options + dappMetadata: { + name: "Example JavaScript Dapp", + url: window.location.href, + }, + infuraAPIKey: process.env.INFURA_API_KEY, + // Other options. }); -// You can also access via window.ethereum +// You can also access via window.ethereum. const ethereum = MMSDK.getProvider(); ethereum.request({ method: "eth_requestAccounts", params: [] }); diff --git a/wallet/how-to/use-sdk/javascript/make-read-only-requests.md b/wallet/how-to/use-sdk/javascript/make-read-only-requests.md index 7117c5baae3..7d6f0336c26 100644 --- a/wallet/how-to/use-sdk/javascript/make-read-only-requests.md +++ b/wallet/how-to/use-sdk/javascript/make-read-only-requests.md @@ -87,11 +87,11 @@ SDK in your dapp. ```javascript sdkOptions={{ - infuraAPIKey: "YOUR-API-KEY", - readonlyRPCMap: { - "0x539": "http://localhost:8545", - }, - // Other options + infuraAPIKey: "YOUR-API-KEY", + readonlyRPCMap: { + "0x539": "http://localhost:8545", + }, + // Other options. }} ``` @@ -110,15 +110,15 @@ The following is an example of using both the Infura API and custom nodes with t ```javascript sdkOptions={{ - infuraAPIKey: "YOUR-API-KEY", - readonlyRPCMap: { - // Custom node - "0x539": "http://localhost:8545", - // Override Infura Mainnet - "0x1": "https://mainnet.infura.io/v3/YOUR-API-KEY", - }, - defaultReadOnlyChainId: "0x1", - // Other options + infuraAPIKey: "YOUR-API-KEY", + readonlyRPCMap: { + // Custom node. + "0x539": "http://localhost:8545", + // Override Infura Mainnet. + "0x1": "https://mainnet.infura.io/v3/YOUR-API-KEY", + }, + defaultReadOnlyChainId: "0x1", + // Other options. } ``` diff --git a/wallet/how-to/use-sdk/javascript/nodejs.md b/wallet/how-to/use-sdk/javascript/nodejs.md index fdeca04458e..ede4133a897 100644 --- a/wallet/how-to/use-sdk/javascript/nodejs.md +++ b/wallet/how-to/use-sdk/javascript/nodejs.md @@ -32,7 +32,7 @@ npm i @metamask/sdk In your project script, add the following to import the SDK: -```javascript +```javascript title="index.js" import { MetaMaskSDK } from "@metamask/sdk"; ``` @@ -40,14 +40,14 @@ import { MetaMaskSDK } from "@metamask/sdk"; Instantiate the SDK using any [options](../../../reference/sdk-js-options.md): -```javascript +```javascript title="index.js" const MMSDK = new MetaMaskSDK({ - dappMetadata: { - name: "Example Node.js Dapp", - url: window.location.href, - }, - infuraAPIKey: process.env.INFURA_API_KEY, - // Other options + dappMetadata: { + name: "Example Node.js Dapp", + url: window.location.href, + }, + infuraAPIKey: process.env.INFURA_API_KEY, + // Other options. }); // You can also access via window.ethereum @@ -83,12 +83,12 @@ You can copy the full Node.js example to get started: import { MetaMaskSDK } from "@metamask/sdk"; const MMSDK = new MetaMaskSDK({ - dappMetadata: { - name: "Example Node.js Dapp", - url: window.location.href, - }, - infuraAPIKey: process.env.INFURA_API_KEY, - // Other options + dappMetadata: { + name: "Example Node.js Dapp", + url: window.location.href, + }, + infuraAPIKey: process.env.INFURA_API_KEY, + // Other options. }); // You can also access via window.ethereum diff --git a/wallet/how-to/use-sdk/javascript/other-web-frameworks.md b/wallet/how-to/use-sdk/javascript/other-web-frameworks.md index e4d044f4724..7c75ba74c5a 100644 --- a/wallet/how-to/use-sdk/javascript/other-web-frameworks.md +++ b/wallet/how-to/use-sdk/javascript/other-web-frameworks.md @@ -33,7 +33,7 @@ npm i @metamask/sdk In your project script, add the following to import the SDK: -```javascript +```javascript title="index.js" import { MetaMaskSDK } from "@metamask/sdk"; ``` @@ -41,14 +41,14 @@ import { MetaMaskSDK } from "@metamask/sdk"; Instantiate the SDK using any [options](../../../reference/sdk-js-options.md): -```javascript +```javascript title="index.js" const MMSDK = new MetaMaskSDK( - dappMetadata: { - name: "Example JavaScript Dapp", - url: window.location.href, - }, - infuraAPIKey: process.env.INFURA_API_KEY, - // Other options + dappMetadata: { + name: "Example JavaScript Dapp", + url: window.location.href, + }, + infuraAPIKey: process.env.INFURA_API_KEY, + // Other options ); // You can also access via window.ethereum @@ -84,12 +84,12 @@ You can copy the full JavaScript example to get started: import { MetaMaskSDK } from "@metamask/sdk"; const MMSDK = new MetaMaskSDK( - dappMetadata: { - name: "Example JavaScript Dapp", - url: window.location.href, - }, - infuraAPIKey: process.env.INFURA_API_KEY, - // Other options + dappMetadata: { + name: "Example JavaScript Dapp", + url: window.location.href, + }, + infuraAPIKey: process.env.INFURA_API_KEY, + // Other options ); // You can also access via window.ethereum diff --git a/wallet/how-to/use-sdk/javascript/pure-js.md b/wallet/how-to/use-sdk/javascript/pure-js.md index c2297c73e27..c0978854676 100644 --- a/wallet/how-to/use-sdk/javascript/pure-js.md +++ b/wallet/how-to/use-sdk/javascript/pure-js.md @@ -16,26 +16,26 @@ To import, instantiate, and use the SDK, you can insert a script in the head sec ```html title="index.html" - ... - - - ... + ... + + + ... ``` diff --git a/wallet/how-to/use-sdk/javascript/react-native.md b/wallet/how-to/use-sdk/javascript/react-native.md index dde1329fe7c..06543c5a3c3 100644 --- a/wallet/how-to/use-sdk/javascript/react-native.md +++ b/wallet/how-to/use-sdk/javascript/react-native.md @@ -82,19 +82,19 @@ In React Native or Expo, update the default Metro configuration file to the foll const defaultConfig = getDefaultConfig(__dirname); const config = { - transformer: { - getTransformOptions: async () => ({ - transform: { - experimentalImportSupport: false, - inlineRequires: true, - }, - }), - }, - resolver: { - extraNodeModules: { - ...require("node-libs-react-native"), - }, + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, + resolver: { + extraNodeModules: { + ...require("node-libs-react-native"), }, + }, }; module.exports = mergeConfig(defaultConfig, config); @@ -107,14 +107,14 @@ In React Native or Expo, update the default Metro configuration file to the foll const config = getDefaultConfig(__dirname); config.resolver.extraNodeModules = { - ...require("node-libs-expo"), + ...require("node-libs-expo"), }; config.transformer.getTransformOptions = async () => ({ - transform: { - experimentalImportSupport: false, - inlineRequires: true, - }, + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, }); module.exports = config; @@ -202,11 +202,11 @@ Connect to MetaMask: ```javascript const connectWallet = async () => { - try { - await connect(); - } catch (error) { - console.error("Failed to connect wallet:", error); - } + try { + await connect(); + } catch (error) { + console.error("Failed to connect wallet:", error); + } }; ``` @@ -214,10 +214,10 @@ Handle your dapp's state: ```javascript useEffect(() => { - // Use the 'account' and 'chainId' returned by 'useSDK' - if (account && chainId) { - // Handle account and network changes - } + // Use the account and chainId returned by useSDK. + if (account && chainId) { + // Handle account and network changes. + } }, [account, chainId]); ``` @@ -225,7 +225,7 @@ Disconnect from MetaMask: ```javascript const disconnectWallet = async () => { - await disconnect(); + await disconnect(); }; ``` diff --git a/wallet/how-to/use-sdk/javascript/react/index.md b/wallet/how-to/use-sdk/javascript/react/index.md index bd7267be7a0..c04da19c9ec 100644 --- a/wallet/how-to/use-sdk/javascript/react/index.md +++ b/wallet/how-to/use-sdk/javascript/react/index.md @@ -41,7 +41,7 @@ npm i @metamask/sdk-react In your project script, add the following to import the SDK: -```javascript +```typescript title="index.tsx" import { MetaMaskProvider } from "@metamask/sdk-react"; ``` @@ -50,32 +50,32 @@ import { MetaMaskProvider } from "@metamask/sdk-react"; Wrap your root component in a `MetaMaskProvider`. For example: -```js +```typescript title="index.tsx" import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import { MetaMaskProvider } from "@metamask/sdk-react"; const root = ReactDOM.createRoot( - document.getElementById("root") as HTMLElement + document.getElementById("root") as HTMLElement ); root.render( - - - - - + + + + + ); ``` @@ -96,39 +96,39 @@ Important options include: Use the SDK by using the `useSDK` hook in your React components. For example: -```js +```typescript title="App.tsx" import { useSDK } from "@metamask/sdk-react"; import React, { useState } from "react"; export const App = () => { - const [account, setAccount] = useState(); - const { sdk, connected, connecting, provider, chainId } = useSDK(); - - const connect = async () => { - try { - const accounts = await sdk?.connect(); - setAccount(accounts?.[0]); - } catch (err) { - console.warn("failed to connect..", err); - } - }; - - return ( -
- - {connected && ( -
- <> - {chainId && `Connected chain: ${chainId}`} -

- {account && `Connected account: ${account}`} - -
- )} + const [account, setAccount] = useState(); + const { sdk, connected, connecting, provider, chainId } = useSDK(); + + const connect = async () => { + try { + const accounts = await sdk?.connect(); + setAccount(accounts?.[0]); + } catch (err) { + console.warn("failed to connect..", err); + } + }; + + return ( +
+ + {connected && ( +
+ <> + {chainId && `Connected chain: ${chainId}`} +

+ {account && `Connected account: ${account}`} +
- ); + )} +
+ ); }; ``` @@ -152,14 +152,14 @@ connect to MetaMask and sign data in a single interaction: ```js const connectAndSign = async () => { - try { - const signResult = await sdk?.connectAndSign({ - msg: "Connect + Sign message", - }); - setResponse(signResult); - } catch (err) { - console.warn("failed to connect..", err); - } + try { + const signResult = await sdk?.connectAndSign({ + msg: "Connect + Sign message", + }); + setResponse(signResult); + } catch (err) { + console.warn("failed to connect..", err); + } }; ``` @@ -180,25 +180,25 @@ import App from "./App"; import { MetaMaskProvider } from "@metamask/sdk-react"; const root = ReactDOM.createRoot( - document.getElementById("root") as HTMLElement + document.getElementById("root") as HTMLElement ); root.render( - - - - - + + + + + ); ``` @@ -210,34 +210,34 @@ import { useSDK } from "@metamask/sdk-react"; import React from "react"; export const App = () => { - const [account, setAccount] = useState(); - const { sdk, connected, connecting, provider, chainId } = useSDK(); - - const connect = async () => { - try { - const accounts = await sdk?.connect(); - setAccount(accounts?.[0]); - } catch (err) { - console.warn("failed to connect..", err); - } - }; - - return ( -
- - {connected && ( -
- <> - {chainId && "Connected chain: ${chainId}"} -

- {account && "Connected account: ${account}"} - -
- )} + const [account, setAccount] = useState(); + const { sdk, connected, connecting, provider, chainId } = useSDK(); + + const connect = async () => { + try { + const accounts = await sdk?.connect(); + setAccount(accounts?.[0]); + } catch (err) { + console.warn("failed to connect..", err); + } + }; + + return ( +
+ + {connected && ( +
+ <> + {chainId && "Connected chain: ${chainId}"} +

+ {account && "Connected account: ${account}"} +
- ); + )} +
+ ); }; ``` diff --git a/wallet/how-to/use-sdk/javascript/react/react-ui.md b/wallet/how-to/use-sdk/javascript/react/react-ui.md index 1a9ed13c2b4..b64709fb610 100644 --- a/wallet/how-to/use-sdk/javascript/react/react-ui.md +++ b/wallet/how-to/use-sdk/javascript/react/react-ui.md @@ -43,7 +43,7 @@ npm i @metamask/sdk-react-ui In your project script, add the following to import the SDK: -```javascript +```javascript title="index.js" import { MetaMaskUIProvider } from "@metamask/sdk-react-ui"; ``` @@ -52,31 +52,31 @@ import { MetaMaskUIProvider } from "@metamask/sdk-react-ui"; Wrap your root component in a `MetaMaskUIProvider`. For example: -```js +```js title="index.js" import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import { MetaMaskUIProvider } from "@metamask/sdk-react-ui"; const root = ReactDOM.createRoot( - document.getElementById("root") as HTMLElement + document.getElementById("root") as HTMLElement ); root.render( - - - - - + + + + + ); ``` @@ -102,16 +102,16 @@ The `@metamask/sdk-react-ui` package provides a pre-styled button, `MetaMaskButt connection to MetaMask. You can use it as follows: -```js +```js title="App.js" import { MetaMaskButton } from "@metamask/sdk-react-ui"; import React, { useState } from "react"; export const App = () => { - return ( -
- -
- ); + return ( +
+ +
+ ); }; ``` @@ -139,24 +139,24 @@ import App from "./App"; import { MetaMaskUIProvider } from "@metamask/sdk-react-ui"; const root = ReactDOM.createRoot( - document.getElementById("root") as HTMLElement + document.getElementById("root") as HTMLElement ); root.render( - - - - - + + + + + ); ``` @@ -165,57 +165,57 @@ root.render( ```javascript title="App.js" import { - MetaMaskButton, - useAccount, - useSDK, - useSignMessage, + MetaMaskButton, + useAccount, + useSDK, + useSignMessage, } from "@metamask/sdk-react-ui"; import "./App.css"; function AppReady() { - const { - data: signData, - isError: isSignError, - isLoading: isSignLoading, - isSuccess: isSignSuccess, - signMessage, - } = useSignMessage({ - message: "gm wagmi frens", - }); - - const { isConnected } = useAccount(); - - return ( -
-
- - {isConnected && ( - <> -
- - {isSignSuccess &&
Signature: {signData}
} - {isSignError &&
Error signing message
} -
- - )} -
-
- ); + const { + data: signData, + isError: isSignError, + isLoading: isSignLoading, + isSuccess: isSignSuccess, + signMessage, + } = useSignMessage({ + message: "gm wagmi frens", + }); + + const { isConnected } = useAccount(); + + return ( +
+
+ + {isConnected && ( + <> +
+ + {isSignSuccess &&
Signature: {signData}
} + {isSignError &&
Error signing message
} +
+ + )} +
+
+ ); } function App() { - const { ready } = useSDK(); + const { ready } = useSDK(); - if (!ready) { - return
Loading...
; - } + if (!ready) { + return
Loading...
; + } - return ; + return ; } export default App; diff --git a/wallet/how-to/use-sdk/mobile/android.md b/wallet/how-to/use-sdk/mobile/android.md index 88b3ae42390..5d3108f1086 100644 --- a/wallet/how-to/use-sdk/mobile/android.md +++ b/wallet/how-to/use-sdk/mobile/android.md @@ -35,7 +35,7 @@ add the following entry to the `dependencies` block: ```gradle title="build.gradle" dependencies { - implementation 'io.metamask.androidsdk:metamask-android-sdk:0.2.1' + implementation "io.metamask.androidsdk:metamask-android-sdk:0.2.1" } ``` @@ -74,18 +74,18 @@ code to your project file: ```kotlin @AndroidEntryPoint class SomeModel(private val repository: ApplicationRepository) { - val ethereum = Ethereum(context) + val ethereum = Ethereum(context) - val dapp = Dapp("Droid Dapp", "https://droiddapp.com") + val dapp = Dapp("Droid Dapp", "https://droiddapp.com") - // This is the same as calling eth_requestAccounts - ethereum.connect(dapp) { result -> - if (result is RequestError) { - Log.e(TAG, "Ethereum connection error: ${result.message}") - } else { - Log.d(TAG, "Ethereum connection result: $result") - } + // This is the same as calling eth_requestAccounts. + ethereum.connect(dapp) { result -> + if (result is RequestError) { + Log.e(TAG, "Ethereum connection error: ${result.message}") + } else { + Log.d(TAG, "Ethereum connection result: $result") } + } } ``` @@ -101,24 +101,24 @@ If you use Hilt, your setup might look like the following: ```kotlin title="EthereumViewModel.kt" @HiltViewModel class EthereumViewModel @Inject constructor( - private val ethereum: Ethereum + private val ethereum: Ethereum ): ViewModel() { - val ethereumState = MediatorLiveData().apply { - addSource(ethereum.ethereumState) { newEthereumState -> - value = newEthereumState - } + val ethereumState = MediatorLiveData().apply { + addSource(ethereum.ethereumState) { newEthereumState -> + value = newEthereumState } + } - // Wrapper function to connect the dapp - fun connect(dapp: Dapp, callback: ((Any?) -> Unit)?) { - ethereum.connect(dapp, callback) - } + // Wrapper function to connect the dapp. + fun connect(dapp: Dapp, callback: ((Any?) -> Unit)?) { + ethereum.connect(dapp, callback) + } - // Wrapper function call all RPC methods - fun sendRequest(request: EthereumRequest, callback: ((Any?) -> Unit)?) { - ethereum.sendRequest(request, callback) - } + // Wrapper function call all RPC methods. + fun sendRequest(request: EthereumRequest, callback: ((Any?) -> Unit)?) { + ethereum.sendRequest(request, callback) + } } ``` @@ -129,13 +129,13 @@ val ethereumViewModel: EthereumViewModel by viewModels() val dapp = Dapp("Droid Dapp", "https://droiddapp.com") -// This is the same as calling eth_requestAccounts +// This is the same as calling eth_requestAccounts. ethereum.connect(dapp) { result -> - if (result is RequestError) { - Log.e(TAG, "Ethereum connection error: ${result.message}") - } else { - Log.d(TAG, "Ethereum connection result: $result") - } + if (result is RequestError) { + Log.e(TAG, "Ethereum connection error: ${result.message}") + } else { + Log.d(TAG, "Ethereum connection result: $result") + } } ``` @@ -156,26 +156,26 @@ The following example gets the user's account balance by calling ```kotlin var balance: String? = null -// Create parameters +// Create parameters. val params: List = listOf( - ethereum.selectedAddress, - // "latest", "earliest" or "pending" (optional) - "latest" + ethereum.selectedAddress, + // "latest", "earliest", or "pending" (optional) + "latest" ) -// Create request +// Create request. val getBalanceRequest = EthereumRequest( - method = EthereumMethod.ETHGETBALANCE.value, - params = params + method = EthereumMethod.ETHGETBALANCE.value, + params = params ) -// Make request +// Make request. ethereum.sendRequest(getBalanceRequest) { result -> - if (result is RequestError) { - // handle error - } else { - balance = result - } + if (result is RequestError) { + // Handle error. + } else { + balance = result + } } ``` @@ -191,16 +191,16 @@ val from = ethereum.selectedAddress val params: List = listOf(from, message) val signRequest = EthereumRequest( - method = EthereumMethod.ETH_SIGN_TYPED_DATA_V4.value, - params = params + method = EthereumMethod.ETH_SIGN_TYPED_DATA_V4.value, + params = params ) ethereum.sendRequest(signRequest) { result -> - if (result is RequestError) { - Log.e(TAG, "Ethereum sign error: ${result.message}") - } else { - Log.d(TAG, "Ethereum sign result: $result") - } + if (result is RequestError) { + Log.e(TAG, "Ethereum sign error: ${result.message}") + } else { + Log.d(TAG, "Ethereum sign result: $result") + } } ``` @@ -210,29 +210,29 @@ The following example sends a transaction by calling [`eth_sendTransaction`](/wallet/reference/eth_sendTransaction). ```kotlin -// Create parameters +// Create parameters. val from = ethereum.selectedAddress val to = "0x0000000000000000000000000000000000000000" val amount = "0x01" val params: Map = mapOf( - "from" to from, - "to" to to, - "amount" to amount + "from" to from, + "to" to to, + "amount" to amount ) -// Create request +// Create request. val transactionRequest = EthereumRequest( - method = EthereumMethod.ETH_SEND_TRANSACTION.value, - params = listOf(params) + method = EthereumMethod.ETH_SEND_TRANSACTION.value, + params = listOf(params) ) -// Make a transaction request +// Make a transaction request. ethereum.sendRequest(transactionRequest) { result -> - if (result is RequestError) { - // handle error - } else { - Log.d(TAG, "Ethereum transaction result: $result") - } + if (result is RequestError) { + // Handle error. + } else { + Log.d(TAG, "Ethereum transaction result: $result") + } } ``` @@ -244,70 +244,66 @@ The following example switches to a new Ethereum chain by calling ```kotlin fun switchChain( - chainId: String, - onSuccess: (message: String) -> Unit, - onError: (message: String, action: (() -> Unit)?) -> Unit + chainId: String, + onSuccess: (message: String) -> Unit, + onError: (message: String, action: (() -> Unit)?) -> Unit ) { - val switchChainParams: Map = mapOf("chainId" to chainId) - val switchChainRequest = EthereumRequest( - method = EthereumMethod.SWITCH_ETHEREUM_CHAIN.value, - params = listOf(switchChainParams) - ) - - ethereum.sendRequest(switchChainRequest) { result -> - if (result is RequestError) { - if (result.code == ErrorType.UNRECOGNIZED_CHAIN_ID.code || result.code == ErrorType.SERVER_ERROR.code) { - val message = "${Network.chainNameFor(chainId)} ($chainId) has not been added to your MetaMask wallet. Add chain?" - - val action: () -> Unit = { - addEthereumChain( - chainId, - onSuccess = { result -> - onSuccess(result) - }, - onError = { error -> - onError(error, null) - } - ) - } - onError(message, action) - } else { - onError("Switch chain error: ${result.message}", null) - } - } else { - onSuccess("Successfully switched to ${Network.chainNameFor(chainId)} ($chainId)") + val switchChainParams: Map = mapOf("chainId" to chainId) + val switchChainRequest = EthereumRequest( + method = EthereumMethod.SWITCH_ETHEREUM_CHAIN.value, + params = listOf(switchChainParams) + ) + + ethereum.sendRequest(switchChainRequest) { result -> + if (result is RequestError) { + if (result.code == ErrorType.UNRECOGNIZED_CHAIN_ID.code || result.code == ErrorType.SERVER_ERROR.code) { + val message = "${Network.chainNameFor(chainId)} ($chainId) has not been added to your MetaMask wallet. Add chain?" + + val action: () -> Unit = { + addEthereumChain( + chainId, + onSuccess = { result -> onSuccess(result) }, + onError = { error -> onError(error, null) } + ) } + onError(message, action) + } else { + onError("Switch chain error: ${result.message}", null) + } + } else { + onSuccess("Successfully switched to ${Network.chainNameFor(chainId)} ($chainId)") } + } } private fun addEthereumChain( - chainId: String, - onSuccess: (message: String) -> Unit, - onError: (message: String) -> Unit + chainId: String, + onSuccess: (message: String) -> Unit, + onError: (message: String) -> Unit ) { - Logger.log("Adding chainId: $chainId") - - val addChainParams: Map = mapOf( - "chainId" to chainId, - "chainName" to Network.chainNameFor(chainId), - "rpcUrls" to Network.rpcUrls(Network.fromChainId(chainId)) - ) - val addChainRequest = EthereumRequest( - method = EthereumMethod.ADD_ETHEREUM_CHAIN.value, - params = listOf(addChainParams) - ) - - ethereum.sendRequest(addChainRequest) { result -> - if (result is RequestError) { - onError("Add chain error: ${result.message}") - } else { - if (chainId == ethereum.chainId) { - onSuccess("Successfully switched to ${Network.chainNameFor(chainId)} ($chainId)") - } else { - onSuccess("Successfully added ${Network.chainNameFor(chainId)} ($chainId)") - } - } + Logger.log("Adding chainId: $chainId") + + val addChainParams: Map = mapOf( + "chainId" to chainId, + "chainName" to Network.chainNameFor(chainId), + "rpcUrls" to Network.rpcUrls(Network.fromChainId(chainId)) + ) + val addChainRequest = EthereumRequest( + method = EthereumMethod.ADD_ETHEREUM_CHAIN.value, + params = listOf(addChainParams) + ) + + ethereum.sendRequest(addChainRequest) { result -> + if (result is RequestError) { + onError("Add chain error: ${result.message}") + } else { + if (chainId == ethereum.chainId) { + onSuccess("Successfully switched to ${Network.chainNameFor(chainId)} ($chainId)") + } else { + onSuccess("Successfully added ${Network.chainNameFor(chainId)} ($chainId)") + } } + } } ``` diff --git a/wallet/how-to/use-sdk/mobile/ios.md b/wallet/how-to/use-sdk/mobile/ios.md index c09c1a4a03f..9056939572e 100644 --- a/wallet/how-to/use-sdk/mobile/ios.md +++ b/wallet/how-to/use-sdk/mobile/ios.md @@ -37,7 +37,7 @@ users to easily connect with their MetaMask Mobile wallet. To add the SDK as a CocoaPods dependency to your project, add the following entry to our Podfile: ```text -pod 'metamask-ios-sdk' +pod "metamask-ios-sdk" ``` Run the following command: @@ -57,10 +57,10 @@ Alternatively, you can add the URL directly in your project's package file: ```swift dependencies: [ - .package( - url: "https://github.com/MetaMask/metamask-ios-sdk", - from: "0.3.0" - ) + .package( + url: "https://github.com/MetaMask/metamask-ios-sdk", + from: "0.3.0" + ) ] ``` @@ -111,23 +111,23 @@ The following example gets the user's account balance by calling [`eth_getBalance`](/wallet/reference/eth_getBalance). ```swift -// Create parameters +// Create parameters. let account = metamaskSDK.account let parameters: [String] = [ - // account to check for balance - account, - // "latest", "earliest" or "pending" (optional) - "latest" + // Account to check for balance. + account, + // "latest", "earliest", or "pending" (optional) + "latest" ] -// Create request +// Create request. let getBalanceRequest = EthereumRequest( - method: .ethGetBalance, - params: parameters + method: .ethGetBalance, + params: parameters ) -// Make request +// Make request. let accountBalance = await metamaskSDK.request(getBalanceRequest) ``` @@ -144,26 +144,26 @@ dictionary directly. Note that `Any` or even `AnyHashable` types aren't supported, since the type must be explicitly known. ```swift -// Create parameters +// Create parameters. let account = metamaskSDK.account let parameters: [String: String] = [ - // receiver address - "to": "0x...", - // sender address - "from": account, - // amount - "value": "0x..." + // Receiver address. + "to": "0x...", + // Sender address. + "from": account, + // Amount to send. + "value": "0x..." ] -// Create request +// Create request. let transactionRequest = EthereumRequest( - method: .ethSendTransaction, - // eth_sendTransaction expects an array parameters object - params: [parameters] + method: .ethSendTransaction, + // eth_sendTransaction expects an array parameters object. + params: [parameters] ) -// Make a transaction request +// Make a transaction request. let transactionResult = await metamaskSDK.request(transactionRequest) ``` @@ -181,48 +181,48 @@ The type can then be represented as a socket packet. ```swift struct Transaction: CodableData { - let to: String - let from: String - let value: String - let data: String? - - init(to: String, from: String, value: String, data: String? = nil) { - self.to = to - self.from = from - self.value = value - self.data = data - } - - func socketRepresentation() -> NetworkData { - [ - "to": to, - "from": from, - "value": value, - "data": data - ] - } + let to: String + let from: String + let value: String + let data: String? + + init(to: String, from: String, value: String, data: String? = nil) { + self.to = to + self.from = from + self.value = value + self.data = data + } + + func socketRepresentation() -> NetworkData { + [ + "to": to, + "from": from, + "value": value, + "data": data + ] + } } -// Create parameters +// Create parameters. let account = metamaskSDK.account let transaction = Transaction( - // receiver address - to: "0x...", - // sender address - from: account, - // amount - value: "0x..." + // Receiver address. + to: "0x...", + // Sender address. + from: account, + // Amount. + value: "0x..." ) -// Create request +// Create request. let transactionRequest = EthereumRequest( - method: .ethSendTransaction, - // eth_sendTransaction expects an array parameters object - params: [transaction] + method: .ethSendTransaction, + // eth_sendTransaction expects an array parameters object. + params: [transaction] ) -// Make a transaction request +// Make a transaction request. let result = await metamaskSDK.request(transactionRequest) ``` diff --git a/wallet/reference/provider-api.md b/wallet/reference/provider-api.md index 7907b4d5c5d..cc45de8cff9 100644 --- a/wallet/reference/provider-api.md +++ b/wallet/reference/provider-api.md @@ -89,31 +89,31 @@ The following is an example of using `request()` to call ```javascript params: [ - { - from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", - to: "0xd46e8dd67c5d32be8058bb8eb970870f07244567", - // 30400 - gas: "0x76c0", - // 10000000000000 - gasPrice: "0x9184e72a000", - // 2441406250 - value: "0x9184e72a", - data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", - }, + { + from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + to: "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + // 30400 + gas: "0x76c0", + // 10000000000000 + gasPrice: "0x9184e72a000", + // 2441406250 + value: "0x9184e72a", + data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", + }, ]; provider // Or window.ethereum if you don't support EIP-6963. - .request({ - method: "eth_sendTransaction", - params, - }) - .then((result) => { - // The result varies by RPC method. - // For example, this method returns a transaction hash hexadecimal string upon success. - }) - .catch((error) => { - // If the request fails, the Promise rejects with an error. - }); + .request({ + method: "eth_sendTransaction", + params, + }) + .then((result) => { + // The result varies by RPC method. + // For example, this method returns a transaction hash hexadecimal string upon success. + }) + .catch((error) => { + // If the request fails, the Promise rejects with an error. + }); ``` ### `_metamask.isUnlocked()` @@ -151,16 +151,16 @@ unmount in React). ```javascript function handleAccountsChanged(accounts) { - // Handle new accounts, or lack thereof. + // Handle new accounts, or lack thereof. } provider // Or window.ethereum if you don't support EIP-6963. - .on("accountsChanged", handleAccountsChanged); + .on("accountsChanged", handleAccountsChanged); // Later provider // Or window.ethereum if you don't support EIP-6963. - .removeListener("accountsChanged", handleAccountsChanged); + .removeListener("accountsChanged", handleAccountsChanged); ``` The first argument of `removeListener` is the event name, and the second argument is @@ -170,7 +170,7 @@ a reference to the function passed to `on` for the event. ```typescript provider // Or window.ethereum if you don't support EIP-6963. - .on("accountsChanged", handler: (accounts: Array) => void); + .on("accountsChanged", handler: (accounts: Array) => void); ``` The provider emits this event when the return value of the @@ -188,7 +188,7 @@ Listen to this event to [handle accounts](../how-to/connect/access-accounts.md#h ```typescript provider // Or window.ethereum if you don't support EIP-6963. - .on("chainChanged", handler: (chainId: string) => void); + .on("chainChanged", handler: (chainId: string) => void); ``` The provider emits this event when the currently connected chain changes. @@ -200,7 +200,7 @@ We strongly recommend reloading the page upon chain changes, unless you have a g ```typescript provider // Or window.ethereum if you don't support EIP-6963. - .on("chainChanged", (chainId) => window.location.reload()); + .on("chainChanged", (chainId) => window.location.reload()); ``` ::: @@ -209,11 +209,11 @@ provider // Or window.ethereum if you don't support EIP-6963. ```typescript interface ConnectInfo { - chainId: string; + chainId: string; } provider // Or window.ethereum if you don't support EIP-6963. - .on("connect", handler: (connectInfo: ConnectInfo) => void); + .on("connect", handler: (connectInfo: ConnectInfo) => void); ``` The provider emits this event when it's first able to submit RPC requests to a chain. @@ -225,7 +225,7 @@ the provider is connected. ```typescript provider // Or window.ethereum if you don't support EIP-6963. - .on("disconnect", handler: (error: ProviderRpcError) => void); + .on("disconnect", handler: (error: ProviderRpcError) => void); ``` The provider emits this event if it becomes unable to submit RPC requests to a chain. @@ -240,12 +240,12 @@ to determine if the provider is disconnected. ```typescript interface ProviderMessage { - type: string; - data: unknown; + type: string; + data: unknown; } provider // Or window.ethereum if you don't support EIP-6963. - .on("message", handler: (message: ProviderMessage) => void); + .on("message", handler: (message: ProviderMessage) => void); ``` The provider emits this event when it receives a message that the user should be notified of. @@ -262,9 +262,9 @@ All errors returned by the MetaMask provider follow this interface: ```typescript interface ProviderRpcError extends Error { - message: string; - code: number; - data?: unknown; + message: string; + code: number; + data?: unknown; } ``` diff --git a/wallet/reference/sdk-js-options.md b/wallet/reference/sdk-js-options.md index 44cabcef751..9cfe96c62a8 100644 --- a/wallet/reference/sdk-js-options.md +++ b/wallet/reference/sdk-js-options.md @@ -112,9 +112,9 @@ This option is mainly used for debugging and testing the SDK. ```javascript dappMetadata: { - name: , - url: , - base64Icon: , + name: , + url: , + base64Icon: , } ``` @@ -123,9 +123,9 @@ dappMetadata: { ```javascript dappMetadata: { - name: "My Dapp", - url: "https://mydapp.com", - base64Icon: "data:image/png;base64,...", + name: "My Dapp", + url: "https://mydapp.com", + base64Icon: "data:image/png;base64,...", } ``` @@ -257,25 +257,25 @@ modals: ```javascript modals: { - onPendingModalDisconnect: () => { - // Custom logic for pending modal disconnect - }, - install: (params) => { - // Custom install modal logic - const { link, debug, installer, terminate, connectWithExtension } = params; - return { - mount: (link) => { /* custom mount logic */ }, - unmount: (shouldTerminate) => { /* custom unmount logic */ }, - }; - }, - otp: ({ debug, onDisconnect }) => { - // Custom OTP modal logic - return { - mount: () => { /* custom mount logic */ }, - updateOTPValue: (otpValue) => { /* custom OTP value update logic */ }, - unmount: () => { /* custom unmount logic */ }, - }; - }, + onPendingModalDisconnect: () => { + // Custom logic for pending modal disconnect. + }, + install: (params) => { + // Custom install modal logic. + const { link, debug, installer, terminate, connectWithExtension } = params; + return { + mount: (link) => { /* Custom mount logic */ }, + unmount: (shouldTerminate) => { /* Custom unmount logic */ }, + }; + }, + otp: ({ debug, onDisconnect }) => { + // Custom OTP modal logic. + return { + mount: () => { /* Custom mount logic */ }, + updateOTPValue: (otpValue) => { /* Custom OTP value update logic */ }, + unmount: () => { /* Custom unmount logic */ }, + }; + }, } ``` @@ -299,9 +299,9 @@ openDeeplink: ```javascript openDeeplink: (link: string) => { - if (canOpenLink) { - Linking.openURL(link); - } + if (canOpenLink) { + Linking.openURL(link); + } } ``` @@ -346,7 +346,7 @@ readonlyRPCMap: ```javascript readonlyRPCMap: { - "0x539": "http://localhost:8545", + "0x539": "http://localhost:8545", } ``` @@ -421,8 +421,8 @@ Sets the preference on [Socket.IO](https://socket.io/docs/v4/) transports. ```javascript ui: { - installer: , - confirm: , + installer: , + confirm: , } ``` diff --git a/wallet/reference/sdk-unity-api.md b/wallet/reference/sdk-unity-api.md index 44afb86fea1..f5288c97da6 100644 --- a/wallet/reference/sdk-unity-api.md +++ b/wallet/reference/sdk-unity-api.md @@ -26,15 +26,15 @@ This method initializes the `MetaMaskWallet` instance and makes it accessible vi You can also pass extra options and parameters to it to customize the wallet instance: ```csharp -// Initialize using default settings +// Initialize using default settings. MetaMaskUnity.Instance.Initialize(); -// Initialize using custom transport and socket provider +// Initialize using custom transport and socket provider. var transport = new MyCustomTransport(); var socketProvider = new MyCustomSocketProvider(); MetaMaskUnity.Instance.Initialize(transport, socketProvider); -// Initialize using custom config, transport and socket provider +// Initialize using custom config, transport and socket provider. var config = myMetaMaskConfig; var transport = new MyCustomTransport(); var socketProvider = new MyCustomSocketProvider(); diff --git a/wallet/tutorials/react-dapp-global-state.md b/wallet/tutorials/react-dapp-global-state.md index edb501f4a16..5fbb4d8930e 100644 --- a/wallet/tutorials/react-dapp-global-state.md +++ b/wallet/tutorials/react-dapp-global-state.md @@ -128,12 +128,12 @@ There are two ways to use ESLint: ```json title="settings.json" { - "eslint.format.enable": true, - "eslint.packageManager": "npm", - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true - }, - "eslint.codeActionsOnSave.mode": "all" + "eslint.format.enable": true, + "eslint.packageManager": "npm", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "eslint.codeActionsOnSave.mode": "all" } ``` @@ -210,155 +210,154 @@ The following code contains comments describing advanced React patterns and how ```tsx title="useMetaMask.tsx" /* eslint-disable @typescript-eslint/no-explicit-any */ import { - useState, - useEffect, - createContext, - PropsWithChildren, - useContext, - useCallback, + useState, + useEffect, + createContext, + PropsWithChildren, + useContext, + useCallback, } from "react"; import detectEthereumProvider from "@metamask/detect-provider"; import { formatBalance } from "~/utils"; interface WalletState { - accounts: any[]; - balance: string; - chainId: string; + accounts: any[]; + balance: string; + chainId: string; } interface MetaMaskContextData { - wallet: WalletState; - hasProvider: boolean | null; - error: boolean; - errorMessage: string; - isConnecting: boolean; - connectMetaMask: () => void; - clearError: () => void; + wallet: WalletState; + hasProvider: boolean | null; + error: boolean; + errorMessage: string; + isConnecting: boolean; + connectMetaMask: () => void; + clearError: () => void; } const disconnectedState: WalletState = { - accounts: [], - balance: "", - chainId: "", + accounts: [], + balance: "", + chainId: "", }; const MetaMaskContext = createContext( - {} as MetaMaskContextData + {} as MetaMaskContextData ); export const MetaMaskContextProvider = ({ children }: PropsWithChildren) => { - const [hasProvider, setHasProvider] = useState(null); - - const [isConnecting, setIsConnecting] = useState(false); - - const [errorMessage, setErrorMessage] = useState(""); - const clearError = () => setErrorMessage(""); - - const [wallet, setWallet] = useState(disconnectedState); - // useCallback ensures that you don't uselessly recreate the _updateWallet function on every render - const _updateWallet = useCallback(async (providedAccounts?: any) => { - const accounts = - providedAccounts || - (await window.ethereum.request({ method: "eth_accounts" })); - - if (accounts.length === 0) { - // If there are no accounts, then the user is disconnected - setWallet(disconnectedState); - return; - } - - const balance = formatBalance( - await window.ethereum.request({ - method: "eth_getBalance", - params: [accounts[0], "latest"], - }) - ); - const chainId = await window.ethereum.request({ - method: "eth_chainId", - }); - - setWallet({ accounts, balance, chainId }); - }, []); - - const updateWalletAndAccounts = useCallback( - () => _updateWallet(), - [_updateWallet] - ); - const updateWallet = useCallback( - (accounts: any) => _updateWallet(accounts), - [_updateWallet] - ); + const [hasProvider, setHasProvider] = useState(null); - /** - * This logic checks if MetaMask is installed. If it is, some event handlers are set up - * to update the wallet state when MetaMask changes. The function returned by useEffect - * is used as a "cleanup": it removes the event handlers whenever the MetaMaskProvider - * is unmounted. - */ - useEffect(() => { - const getProvider = async () => { - const provider = await detectEthereumProvider({ silent: true }); - setHasProvider(Boolean(provider)); - - if (provider) { - updateWalletAndAccounts(); - window.ethereum.on("accountsChanged", updateWallet); - window.ethereum.on("chainChanged", updateWalletAndAccounts); - } - }; - - getProvider(); - - return () => { - window.ethereum?.removeListener("accountsChanged", updateWallet); - window.ethereum?.removeListener( - "chainChanged", - updateWalletAndAccounts - ); - }; - }, [updateWallet, updateWalletAndAccounts]); - - const connectMetaMask = async () => { - setIsConnecting(true); - - try { - const accounts = await window.ethereum.request({ - method: "eth_requestAccounts", - }); - clearError(); - updateWallet(accounts); - } catch (err: any) { - setErrorMessage(err.message); - } - setIsConnecting(false); - }; + const [isConnecting, setIsConnecting] = useState(false); - return ( - - {children} - + const [errorMessage, setErrorMessage] = useState(""); + const clearError = () => setErrorMessage(""); + + const [wallet, setWallet] = useState(disconnectedState); + // useCallback ensures that you don't uselessly recreate the _updateWallet function on every render. + const _updateWallet = useCallback(async (providedAccounts?: any) => { + const accounts = + providedAccounts || + (await window.ethereum.request({ method: "eth_accounts" })); + + if (accounts.length === 0) { + // If there are no accounts, then the user is disconnected. + setWallet(disconnectedState); + return; + } + + const balance = formatBalance( + await window.ethereum.request({ + method: "eth_getBalance", + params: [accounts[0], "latest"], + }) ); + const chainId = await window.ethereum.request({ + method: "eth_chainId", + }); + + setWallet({ accounts, balance, chainId }); + }, []); + + const updateWalletAndAccounts = useCallback( + () => _updateWallet(), + [_updateWallet] + ); + const updateWallet = useCallback( + (accounts: any) => _updateWallet(accounts), + [_updateWallet] + ); + + /** + * This logic checks if MetaMask is installed. If it is, some event handlers are set up to update + * the wallet state when MetaMask changes. The function returned by useEffect is used as a + * "cleanup"; it removes the event handlers whenever the MetaMaskProvider is unmounted. + */ + useEffect(() => { + const getProvider = async () => { + const provider = await detectEthereumProvider({ silent: true }); + setHasProvider(Boolean(provider)); + + if (provider) { + updateWalletAndAccounts(); + window.ethereum.on("accountsChanged", updateWallet); + window.ethereum.on("chainChanged", updateWalletAndAccounts); + } + }; + + getProvider(); + + return () => { + window.ethereum?.removeListener("accountsChanged", updateWallet); + window.ethereum?.removeListener( + "chainChanged", + updateWalletAndAccounts + ); + }; + }, [updateWallet, updateWalletAndAccounts]); + + const connectMetaMask = async () => { + setIsConnecting(true); + + try { + const accounts = await window.ethereum.request({ + method: "eth_requestAccounts", + }); + clearError(); + updateWallet(accounts); + } catch (err: any) { + setErrorMessage(err.message); + } + setIsConnecting(false); + }; + + return ( + + {children} + + ); }; export const useMetaMask = () => { - const context = useContext(MetaMaskContext); - if (context === undefined) { - throw new Error( - "useMetaMask must be used within a MetaMaskContextProvider" - ); - } - return context; + const context = useContext(MetaMaskContext); + if (context === undefined) { + throw new Error( + "useMetaMask must be used within a MetaMaskContextProvider" + ); + } + return context; }; ``` @@ -396,15 +395,15 @@ import { MetaMaskError } from "./components/MetaMaskError"; import { MetaMaskContextProvider } from "./hooks/useMetaMask"; export const App = () => { - return ( - -
- - - -
-
- ); + return ( + +
+ + + +
+
+ ); }; ``` @@ -425,42 +424,37 @@ import { formatAddress } from "~/utils"; import styles from "./Navigation.module.css"; export const Navigation = () => { - const { wallet, hasProvider, isConnecting, connectMetaMask } = - useMetaMask(); - - return ( -
-
-
Vite + React & MetaMask
-
- {!hasProvider && ( - - Install MetaMask - - )} - {window.ethereum?.isMetaMask && - wallet.accounts.length < 1 && ( - - )} - {hasProvider && wallet.accounts.length > 0 && ( - - {formatAddress(wallet.accounts[0])} - - )} -
-
+ const { wallet, hasProvider, isConnecting, connectMetaMask } = + useMetaMask(); + + return ( +
+
+
Vite + React & MetaMask
+
+ {!hasProvider && ( + Install MetaMask + )} + {window.ethereum?.isMetaMask && + wallet.accounts.length < 1 && ( + + )} + {hasProvider && wallet.accounts.length > 0 && ( + + {formatAddress(wallet.accounts[0])} + + )}
- ); +
+
+ ); }; ``` @@ -474,7 +468,7 @@ Also, the `formatAddress` function formats the wallet address for display purpos ```ts { - formatAddress(wallet.accounts[0]); + formatAddress(wallet.accounts[0]); } ``` @@ -483,17 +477,17 @@ Update `/src/utils/index.tsx` to the following: ```ts title="utils/index.ts" export const formatBalance = (rawBalance: string) => { - const balance = (parseInt(rawBalance) / 1000000000000000000).toFixed(2); - return balance; + const balance = (parseInt(rawBalance) / 1000000000000000000).toFixed(2); + return balance; }; export const formatChainAsNum = (chainIdHex: string) => { - const chainIdNum = parseInt(chainIdHex); - return chainIdNum; + const chainIdNum = parseInt(chainIdHex); + return chainIdNum; }; export const formatAddress = (addr: string) => { - return `${addr.substring(0, 8)}...`; + return `${addr.substring(0, 8)}...`; }; ``` @@ -519,22 +513,20 @@ import { formatChainAsNum } from "~/utils"; import styles from "./Display.module.css"; export const Display = () => { - const { wallet } = useMetaMask(); - - return ( -
- {wallet.accounts.length > 0 && ( - <> -
Wallet Accounts: {wallet.accounts[0]}
-
Wallet Balance: {wallet.balance}
-
Hex ChainId: {wallet.chainId}
-
- Numeric ChainId: {formatChainAsNum(wallet.chainId)} -
- - )} -
- ); + const { wallet } = useMetaMask(); + + return ( +
+ {wallet.accounts.length > 0 && ( + <> +
Wallet Accounts: {wallet.accounts[0]}
+
Wallet Balance: {wallet.balance}
+
Hex ChainId: {wallet.chainId}
+
Numeric ChainId: {formatChainAsNum(wallet.chainId)}
+ + )} +
+ ); }; ``` @@ -560,19 +552,19 @@ import { useMetaMask } from "~/hooks/useMetaMask"; import styles from "./MetaMaskError.module.css"; export const MetaMaskError = () => { - const { error, errorMessage, clearError } = useMetaMask(); - return ( -
- {error && ( -
- Error: {errorMessage} -
- )} + const { error, errorMessage, clearError } = useMetaMask(); + return ( +
+ {error && ( +
+ Error: {errorMessage}
- ); + )} +
+ ); }; ``` diff --git a/wallet/tutorials/react-dapp-local-state.md b/wallet/tutorials/react-dapp-local-state.md index 2da77d98df3..b276928de5c 100644 --- a/wallet/tutorials/react-dapp-local-state.md +++ b/wallet/tutorials/react-dapp-local-state.md @@ -70,11 +70,11 @@ To start with a blank slate, replace the code in `src/App.tsx` with the followin import "./App.css"; const App = () => { - return ( -
- -
- ); + return ( +
+ +
+ ); }; export default App; @@ -87,7 +87,7 @@ Update `src/vite-env.d.ts` to the following: /// interface Window { - ethereum: any; + ethereum: any; } ``` @@ -95,14 +95,14 @@ Also, update `src/App.css` to the following: ```css title="App.css" .App { - display: flex; - flex-direction: column; - place-items: center; - min-width: 100vw; - min-height: 100vh; + display: flex; + flex-direction: column; + place-items: center; + min-width: 100vw; + min-height: 100vh; } button { - margin-top: 0.5em; + margin-top: 0.5em; } ``` @@ -123,21 +123,21 @@ import "./App.css"; let injectedProvider = false; if (typeof window.ethereum !== "undefined") { - injectedProvider = true; - console.log(window.ethereum); + injectedProvider = true; + console.log(window.ethereum); } const isMetaMask = injectedProvider ? window.ethereum.isMetaMask : false; const App = () => { - return ( -
-

- Injected Provider {injectedProvider ? "DOES" : "DOES NOT"} Exist -

- {isMetaMask && } -
- ); + return ( +
+

+ Injected Provider {injectedProvider ? "DOES" : "DOES NOT"} Exist +

+ {isMetaMask && } +
+ ); }; export default App; @@ -183,27 +183,27 @@ import { useState, useEffect } from "react"; import detectEthereumProvider from "@metamask/detect-provider"; const App = () => { - const [hasProvider, setHasProvider] = useState(null); - - useEffect(() => { - const getProvider = async () => { - const provider = await detectEthereumProvider({ silent: true }); - console.log(provider); - // transform provider to true or false - setHasProvider(Boolean(provider)); - }; - - getProvider(); - }, []); - - return ( -
-
- Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist -
- {hasProvider && } -
- ); + const [hasProvider, setHasProvider] = useState(null); + + useEffect(() => { + const getProvider = async () => { + const provider = await detectEthereumProvider({ silent: true }); + console.log(provider); + // Transform provider to true or false. + setHasProvider(Boolean(provider)); + }; + + getProvider(); + }, []); + + return ( +
+
+ Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist +
+ {hasProvider && } +
+ ); }; export default App; @@ -249,45 +249,45 @@ import { useState, useEffect } from "react"; import detectEthereumProvider from "@metamask/detect-provider"; const App = () => { - const [hasProvider, setHasProvider] = useState(null); - const initialState = { accounts: [] }; /* New */ - const [wallet, setWallet] = useState(initialState); /* New */ - - useEffect(() => { - const getProvider = async () => { - const provider = await detectEthereumProvider({ silent: true }); - setHasProvider(Boolean(provider)); - }; - - getProvider(); - }, []); - - const updateWallet = async (accounts: any) => { /* New */ - setWallet({ accounts }); /* New */ - }; /* New */ - - const handleConnect = async () => { /* New */ - let accounts = await window.ethereum.request({ /* New */ - method: "eth_requestAccounts", /* New */ - }); /* New */ - updateWallet(accounts); /* New */ - }; /* New */ - - return ( -
-
- Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist -
- - {hasProvider && ( /* Updated */ - - )} - - {wallet.accounts.length > 0 && ( /* New */ -
Wallet Accounts: {wallet.accounts[0]}
- )} -
- ); + const [hasProvider, setHasProvider] = useState(null); + const initialState = { accounts: [] }; /* New */ + const [wallet, setWallet] = useState(initialState); /* New */ + + useEffect(() => { + const getProvider = async () => { + const provider = await detectEthereumProvider({ silent: true }); + setHasProvider(Boolean(provider)); + }; + + getProvider(); + }, []); + + const updateWallet = async (accounts: any) => { /* New */ + setWallet({ accounts }); /* New */ + }; /* New */ + + const handleConnect = async () => { /* New */ + let accounts = await window.ethereum.request({ /* New */ + method: "eth_requestAccounts", /* New */ + }); /* New */ + updateWallet(accounts); /* New */ + }; /* New */ + + return ( +
+
+ Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist +
+ + {hasProvider && ( /* Updated */ + + )} + + {wallet.accounts.length > 0 && ( /* New */ +
Wallet Accounts: {wallet.accounts[0]}
+ )} +
+ ); }; export default App; @@ -337,69 +337,69 @@ import { useState, useEffect } from "react"; import detectEthereumProvider from "@metamask/detect-provider"; const App = () => { - const [hasProvider, setHasProvider] = useState(null); - const initialState = { accounts: [] }; - const [wallet, setWallet] = useState(initialState); - - useEffect(() => { - const refreshAccounts = (accounts: any) => { /* New */ - if (accounts.length > 0) { /* New */ - updateWallet(accounts); /* New */ - } else { /* New */ - // if length 0, user is disconnected /* New */ - setWallet(initialState); /* New */ - } /* New */ - }; /* New */ - - const getProvider = async () => { - const provider = await detectEthereumProvider({ silent: true }); - setHasProvider(Boolean(provider)); - - if (provider) { /* New */ - const accounts = await window.ethereum.request( /* New */ - { method: "eth_accounts" } /* New */ - ); /* New */ - refreshAccounts(accounts); /* New */ - window.ethereum.on( /* New */ - "accountsChanged", /* New */ - refreshAccounts /* New */ - ); /* New */ - } /* New */ - }; - - getProvider(); - return () => { /* New */ - window.ethereum?.removeListener("accountsChanged", refreshAccounts); - }; /* New */ - }, []); - - const updateWallet = async (accounts: any) => { - setWallet({ accounts }); - }; - - const handleConnect = async () => { - let accounts = await window.ethereum.request({ - method: "eth_requestAccounts", - }); - updateWallet(accounts); + const [hasProvider, setHasProvider] = useState(null); + const initialState = { accounts: [] }; + const [wallet, setWallet] = useState(initialState); + + useEffect(() => { + const refreshAccounts = (accounts: any) => { /* New */ + if (accounts.length > 0) { /* New */ + updateWallet(accounts); /* New */ + } else { /* New */ + // If length 0, user is disconnected. /* New */ + setWallet(initialState); /* New */ + } /* New */ + }; /* New */ + + const getProvider = async () => { + const provider = await detectEthereumProvider({ silent: true }); + setHasProvider(Boolean(provider)); + + if (provider) { /* New */ + const accounts = await window.ethereum.request( /* New */ + { method: "eth_accounts" } /* New */ + ); /* New */ + refreshAccounts(accounts); /* New */ + window.ethereum.on( /* New */ + "accountsChanged", /* New */ + refreshAccounts /* New */ + ); /* New */ + } /* New */ }; - return ( -
-
- Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist -
- - {window.ethereum?.isMetaMask && /* Updated */ - wallet.accounts.length < 1 && ( - - )} - - {wallet.accounts.length > 0 && ( -
Wallet Accounts: {wallet.accounts[0]}
- )} -
- ); + getProvider(); + return () => { /* New */ + window.ethereum?.removeListener("accountsChanged", refreshAccounts); + }; /* New */ + }, []); + + const updateWallet = async (accounts: any) => { + setWallet({ accounts }); + }; + + const handleConnect = async () => { + let accounts = await window.ethereum.request({ + method: "eth_requestAccounts", + }); + updateWallet(accounts); + }; + + return ( +
+
+ Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist +
+ + {window.ethereum?.isMetaMask && /* Updated */ + wallet.accounts.length < 1 && ( + + )} + + {wallet.accounts.length > 0 && ( +
Wallet Accounts: {wallet.accounts[0]}
+ )} +
+ ); }; export default App; @@ -434,13 +434,13 @@ Create a new file at `src/utils/index.tsx` with the following code: ```tsx title="index.tsx" export const formatBalance = (rawBalance: string) => { - const balance = (parseInt(rawBalance) / 1000000000000000000).toFixed(2); - return balance; + const balance = (parseInt(rawBalance) / 1000000000000000000).toFixed(2); + return balance; }; export const formatChainAsNum = (chainIdHex: string) => { - const chainIdNum = parseInt(chainIdHex); - return chainIdNum; + const chainIdNum = parseInt(chainIdHex); + return chainIdNum; }; ``` @@ -460,102 +460,89 @@ You'll also create a function called `formatBalance`. Update `src/App.tsx` to the following: -```tsx title="App.tsx" {3,8,21-23,35,43,48-55,74,76-78} showLineNumbers +```tsx title="App.tsx" {3,8,21-23,35,43,48-55,74,76-79} showLineNumbers import "./App.css"; import { useState, useEffect } from "react"; -import { formatBalance, formatChainAsNum } from "./utils"; /* New */ +import { formatBalance, formatChainAsNum } from "./utils"; /* New */ import detectEthereumProvider from "@metamask/detect-provider"; const App = () => { - const [hasProvider, setHasProvider] = useState(null); - const initialState = { - accounts: [], - balance: "", - chainId: "", - }; /* Updated */ - const [wallet, setWallet] = useState(initialState); - - useEffect(() => { - const refreshAccounts = (accounts: any) => { - if (accounts.length > 0) { - updateWallet(accounts); - } else { - // if length 0, user is disconnected - setWallet(initialState); - } - }; - - const refreshChain = (chainId: any) => { /* New */ - setWallet((wallet) => ({ ...wallet, chainId })); /* New */ - }; /* New */ - - const getProvider = async () => { - const provider = await detectEthereumProvider({ silent: true }); - setHasProvider(Boolean(provider)); - - if (provider) { - const accounts = await window.ethereum.request({ - method: "eth_accounts", - }); - refreshAccounts(accounts); - window.ethereum.on("accountsChanged", refreshAccounts); - window.ethereum.on("chainChanged", refreshChain); /* New */ - } - }; - - getProvider(); - - return () => { - window.ethereum?.removeListener("accountsChanged", refreshAccounts); - window.ethereum?.removeListener( - "chainChanged", - refreshChain - ); /* New */ - }; - }, []); - - const updateWallet = async (accounts: any) => { - const balance = formatBalance( - await window.ethereum!.request({ /* New */ - method: "eth_getBalance", /* New */ - params: [accounts[0], "latest"], /* New */ - }) - ); /* New */ - const chainId = await window.ethereum!.request({ /* New */ - method: "eth_chainId", /* New */ - }); /* New */ - setWallet({ accounts, balance, chainId }); /* Updated */ + const [hasProvider, setHasProvider] = useState(null); + const initialState = { accounts: [], balance: "", chainId: "", }; /* Updated */ + const [wallet, setWallet] = useState(initialState); + + useEffect(() => { + const refreshAccounts = (accounts: any) => { + if (accounts.length > 0) { + updateWallet(accounts); + } else { + // If length 0, user is disconnected. + setWallet(initialState); + } }; - const handleConnect = async () => { - let accounts = await window.ethereum.request({ - method: "eth_requestAccounts", + const refreshChain = (chainId: any) => { /* New */ + setWallet((wallet) => ({ ...wallet, chainId })); /* New */ + }; /* New */ + + const getProvider = async () => { + const provider = await detectEthereumProvider({ silent: true }); + setHasProvider(Boolean(provider)); + + if (provider) { + const accounts = await window.ethereum.request({ + method: "eth_accounts", }); - updateWallet(accounts); + refreshAccounts(accounts); + window.ethereum.on("accountsChanged", refreshAccounts); + window.ethereum.on("chainChanged", refreshChain); /* New */ + } }; - return ( -
-
- Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist -
- - {window.ethereum?.isMetaMask && wallet.accounts.length < 1 && ( - - )} - - {wallet.accounts.length > 0 && ( - <> {/* New */} -
Wallet Accounts: {wallet.accounts[0]}
-
Wallet Balance: {wallet.balance}
{/* New */} -
Hex ChainId: {wallet.chainId}
{/* New */} -
- Numeric ChainId: {formatChainAsNum(wallet.chainId)} -
{/* New */} - - )} -
- ); + getProvider(); + + return () => { + window.ethereum?.removeListener("accountsChanged", refreshAccounts); + window.ethereum?.removeListener("chainChanged", refreshChain); /* New */ + }; + }, []); + + const updateWallet = async (accounts: any) => { + const balance = formatBalance(await window.ethereum!.request({ /* New */ + method: "eth_getBalance", /* New */ + params: [accounts[0], "latest"], /* New */ + })); /* New */ + const chainId = await window.ethereum!.request({ /* New */ + method: "eth_chainId", /* New */ + }); /* New */ + setWallet({ accounts, balance, chainId }); /* Updated */ + }; + + const handleConnect = async () => { + let accounts = await window.ethereum.request({ + method: "eth_requestAccounts", + }); + updateWallet(accounts); + }; + + return ( +
+
Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist
+ + {window.ethereum?.isMetaMask && wallet.accounts.length < 1 && ( + + )} + + {wallet.accounts.length > 0 && ( + <> {/* New */} +
Wallet Accounts: {wallet.accounts[0]}
+
Wallet Balance: {wallet.balance}
{/* New */} +
Hex ChainId: {wallet.chainId}
{/* New */} +
Numeric ChainId: {formatChainAsNum(wallet.chainId)}
{/* New */} {/* New */} + {/* New */} + )} +
+ ); }; export default App; @@ -602,118 +589,109 @@ the error, and set `error` back to `false` once the message is resolved. Update `src/App.tsx` to the following: -```tsx title="App.tsx" {11-13,62-64,67-75,97-102} showLineNumbers +```tsx title="App.tsx" {11-13,62-64,67-75,84,96-100} showLineNumbers import "./App.css"; import { useState, useEffect } from "react"; import { formatBalance, formatChainAsNum } from "./utils"; import detectEthereumProvider from "@metamask/detect-provider"; const App = () => { - const [hasProvider, setHasProvider] = useState(null); - const initialState = { accounts: [], balance: "", chainId: "" }; - const [wallet, setWallet] = useState(initialState); - - const [isConnecting, setIsConnecting] = useState(false); /* New */ - const [error, setError] = useState(false); /* New */ - const [errorMessage, setErrorMessage] = useState(""); /* New */ - - useEffect(() => { - const refreshAccounts = (accounts: any) => { - if (accounts.length > 0) { - updateWallet(accounts); - } else { - // if length 0, user is disconnected - setWallet(initialState); - } - }; - - const refreshChain = (chainId: any) => { - setWallet((wallet) => ({ ...wallet, chainId })); - }; - - const getProvider = async () => { - const provider = await detectEthereumProvider({ silent: true }); - setHasProvider(Boolean(provider)); - - if (provider) { - const accounts = await window.ethereum.request({ - method: "eth_accounts", - }); - refreshAccounts(accounts); - window.ethereum.on("accountsChanged", refreshAccounts); - window.ethereum.on("chainChanged", refreshChain); - } - }; - - getProvider(); - - return () => { - window.ethereum?.removeListener("accountsChanged", refreshAccounts); - window.ethereum?.removeListener("chainChanged", refreshChain); - }; - }, []); - - const updateWallet = async (accounts: any) => { - const balance = formatBalance( - await window.ethereum!.request({ - method: "eth_getBalance", - params: [accounts[0], "latest"], - }) - ); - const chainId = await window.ethereum!.request({ - method: "eth_chainId", - }); - setWallet({ accounts, balance, chainId }); + const [hasProvider, setHasProvider] = useState(null); + const initialState = { accounts: [], balance: "", chainId: "" }; + const [wallet, setWallet] = useState(initialState); + + const [isConnecting, setIsConnecting] = useState(false); /* New */ + const [error, setError] = useState(false); /* New */ + const [errorMessage, setErrorMessage] = useState(""); /* New */ + + useEffect(() => { + const refreshAccounts = (accounts: any) => { + if (accounts.length > 0) { + updateWallet(accounts); + } else { + // If length 0, user is disconnected. + setWallet(initialState); + } }; - const handleConnect = async () => { /* Updated */ - setIsConnecting(true); /* New */ - await window.ethereum - .request({ /* Updated */ - method: "eth_requestAccounts", - }) - .then((accounts: []) => { /* New */ - setError(false); /* New */ - updateWallet(accounts); /* New */ - }) /* New */ - .catch((err: any) => { /* New */ - setError(true); /* New */ - setErrorMessage(err.message); /* New */ - }); /* New */ - setIsConnecting(false); /* New */ + const refreshChain = (chainId: any) => { + setWallet((wallet) => ({ ...wallet, chainId })); }; - const disableConnect = Boolean(wallet) && isConnecting; - - return ( -
-
- Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist -
- - {window.ethereum?.isMetaMask && wallet.accounts.length < 1 && ( /* Updated */ - - )} - - {wallet.accounts.length > 0 && ( - <> -
Wallet Accounts: {wallet.accounts[0]}
-
Wallet Balance: {wallet.balance}
-
Hex ChainId: {wallet.chainId}
-
- Numeric ChainId: {formatChainAsNum(wallet.chainId)} -
- - )} - {error && ( /* New code block */ -
setError(false)}> - Error: {errorMessage} -
- )} -
+ const getProvider = async () => { + const provider = await detectEthereumProvider({ silent: true }); + setHasProvider(Boolean(provider)); + + if (provider) { + const accounts = await window.ethereum.request({method: "eth_accounts"}); + refreshAccounts(accounts); + window.ethereum.on("accountsChanged", refreshAccounts); + window.ethereum.on("chainChanged", refreshChain); + } + }; + + getProvider(); + + return () => { + window.ethereum?.removeListener("accountsChanged", refreshAccounts); + window.ethereum?.removeListener("chainChanged", refreshChain); + }; + }, []); + + const updateWallet = async (accounts: any) => { + const balance = formatBalance( + await window.ethereum!.request({ + method: "eth_getBalance", + params: [accounts[0], "latest"], + }) ); + const chainId = await window.ethereum!.request({ + method: "eth_chainId", + }); + setWallet({ accounts, balance, chainId }); + }; + + const handleConnect = async () => { /* Updated */ + setIsConnecting(true); /* New */ + await window.ethereum.request({ /* Updated */ + method: "eth_requestAccounts", + }) + .then((accounts: []) => { /* New */ + setError(false); /* New */ + updateWallet(accounts); /* New */ + }) /* New */ + .catch((err: any) => { /* New */ + setError(true); /* New */ + setErrorMessage(err.message); /* New */ + }); /* New */ + setIsConnecting(false); /* New */ + }; + + const disableConnect = Boolean(wallet) && isConnecting; + + return ( +
+
Injected Provider {hasProvider ? "DOES" : "DOES NOT"} Exist
+ + {window.ethereum?.isMetaMask && wallet.accounts.length < 1 && ( /* Updated */ + + )} + + {wallet.accounts.length > 0 && ( + <> +
Wallet Accounts: {wallet.accounts[0]}
+
Wallet Balance: {wallet.balance}
+
Hex ChainId: {wallet.chainId}
+
Numeric ChainId: {formatChainAsNum(wallet.chainId)}
+ + )} + {error && ( /* New code block */ +
setError(false)}> + Error: {errorMessage} +
+ )} +
+ ); }; export default App;