description | sidebar_position |
---|---|
See the Snaps API reference. |
1 |
import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem";
Snaps can communicate with and modify the functionality of MetaMask using the Snaps API. To call each method (except the interactive UI methods), you must first request permission in the Snap manifest file.
:::note See the Wallet API for Snaps for methods that dapps can call to communicate with Snaps. :::
Displays a dialog in the MetaMask UI.
An object containing the contents of the dialog:
type
- (Optional) The type of dialog. Not providing a type will create a fully custom dialog. Possible values are:"alert"
- An alert that can only be acknowledged."confirmation"
- A confirmation that can be accepted or rejected."prompt"
- A prompt where the user can enter a text response.
- One of:
content
- The content of the alert, as a custom UI component.id
- The ID of an interactive interface.
placeholder
- Only used for"prompt"
dialogs. Text that will be in the input field when nothing is typed.
Return value depends on the dialog type
:
"alert"
- None."confirmation"
-true
if the confirmation was accepted,false
otherwise."prompt"
- The text entered by the user if the prompt was submitted ornull
if the prompt was rejected or closed. If the user does not enter any text and submits the prompt, the value is an empty string.
import { Box, Heading, Text } from "@metamask/snaps-sdk/jsx";
const walletAddress = await snap.request({
method: "snap_dialog",
params: {
type: "prompt",
content: (
<Box>
<Heading>What is the wallet address?</Heading>
<Text>Please enter the wallet address to be monitored</Text>
</Box>
),
placeholder: "0x123...",
},
});
// walletAddress will be a string containing the address entered by the user.
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...",
},
})
// walletAddress will be a string containing the address entered by the user.
:::danger important If you call this method, you receive the user's parent key for the derivation path they request. You're managing the user's keys and assets on their behalf. Their safety is your responsibility. :::
Enables you to manage users' non-EVM accounts by deriving
the SLIP-10 keys
specified by the path
and curve
parameters.
The keys are derived using the entropy from the user's Secret Recovery Phrase.
If the keys you want to derive conform to the BIP-44 structure,
use snap_getBip44Entropy
instead.
Otherwise, use this method.
This method is designed to be used with the
@metamask/key-tree
module.
@metamask/key-tree
can help you get the
extended private keys
for user addresses, but it's your responsibility to know how to use those keys to, for example,
derive an address for the relevant protocol or sign a transaction for the user.
An object containing:
path
- An array, starting withm
, containing the BIP-32 derivation path to the key to retrieve. For example,["m", "44'", "60'"]
.curve
- The curve to use for the key derivation. Must be"ed25519"
or"secp256k1"
.
An object representing the SLIP-10 HD tree node and containing its corresponding key material:
depth
- The 0-indexed path depth of the node.parentFingerprint
- The fingerprint of the parent key, or 0 if this is a root node.index
- The index of the node, or 0 if this is a root node.privateKey
- The private key of the node.publicKey
- The public key of the node.chainCode
- The chain code of the node.curve
- The name of the curve used by the node:"ed25519"
or"secp256k1"
.
"initialPermissions": {
"snap_getBip32Entropy": [
{
"path": ["m", "44'", "3'"],
"curve": "secp256k1" // Or "ed25519"
}
]
}
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",
},
})
// Next, create an instance of a SLIP-10 node for the Dogecoin node.
const dogecoinSlip10Node = await SLIP10Node.fromJSON(dogecoinNode)
// m/44'/3'/0'
const accountKey0 = await dogecoinSlip10Node.derive(["bip32:0'"])
// m/44'/3'/1'
const accountKey1 = await dogecoinSlip10Node.derive(["bip32:1'"])
// Now, you can ask the user to sign transactions, etc.
Gets the BIP-32 public key for the
derivation path specified by the path
parameter.
Note that this returns the public key, not the extended public key (xpub
), or Ethereum address.
An object containing:
path
- An array, starting withm
, containing the BIP-32 derivation path to the public key to retrieve. For example,["m", "44'", "60'"]
.curve
- The curve to use for the key derivation. Must be"ed25519"
or"secp256k1"
.compressed
- Indicates whether the public key should be compressed. The default isfalse
.
The public key as hexadecimal string.
"initialPermissions": {
"snap_getBip32PublicKey": [
{
"path": ["m", "44'", "3'", "0'", "0", "0"],
"curve": "secp256k1"
}
]
}
// 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,
},
})
// "0x..."
console.log(dogecoinPublicKey)
:::danger important If you call this method, you receive the user's parent key for the protocol they request. You're managing the user's keys and assets on their behalf. Their safety is your responsibility. :::
Enables you to manage users' non-EVM accounts by deriving
the BIP-44 keys
specified by the coinType
parameter.
The keys are derived using the entropy from the user's Secret Recovery Phrase.
If the keys you want to derive don't conform to the BIP-44 structure, use
snap_getBip32Entropy
instead.
:::note See SLIP-44 for the list of available protocols and their coin types. To register a new coin type, create a pull request on SLIP-44. :::
This method is designed to be used with the
@metamask/key-tree
module.
@metamask/key-tree
can help you get the
extended private keys
for user addresses, but it's your responsibility to know how to use those keys to, for example,
derive an address for the relevant protocol or sign a transaction for the user.
An object containing coinType
, the BIP-44 coin type to get the entropy for.
:::note
Coin type 60 is reserved for MetaMask externally owned accounts and blocked for Snaps.
To connect to MetaMask accounts in a Snap, use
endowment:ethereum-provider
and
eth_requestAccounts
.
:::
An object representing the
BIP-44 coin_type
HD tree node
and containing its corresponding key material:
coin_type
- The BIP-44 coin type value of the node.depth
- The 0-indexed BIP-44 path depth of the node. Since this is acoin_type
node, the depth is2
.privateKey
- The hexadecimal-encoded string representation of the private key for the node.publicKey
- The hexadecimal-encoded string representation of the public key for the node.chainCode
- The hexadecimal-encoded string representation of the chain code for the node.path
- A human-readable representation of the BIP-44 HD tree path of the node. Since this is acoin_type
node, the path is of the formm/44'/coin_type'
.
"initialPermissions": {
"snap_getBip44Entropy": [
{
"coinType": 3
}
]
}
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,
},
})
// Next, create an address key deriver function for the Dogecoin coin_type node.
// In this case, its path is: m/44'/3'/0'/0/address_index
const deriveDogecoinAddress = await getBIP44AddressKeyDeriver(dogecoinNode)
// These are BIP-44 nodes containing the extended private keys for the respective derivation paths.
// m/44'/3'/0'/0/0
const addressKey0 = await deriveDogecoinAddress(0)
// m/44'/3'/0'/0/1
const addressKey1 = await deriveDogecoinAddress(1)
// Now, you can ask the user to sign transactions, etc.
Gets the locked status of the Snaps client.
It is useful to check if MetaMask is locked in the following situations:
- When running background operations that require MetaMask to be unlocked, for example, accessing encrypted state. If MetaMask is locked, the user gets an unexpected password request.
- When displaying a dialog. Dialogs do not work when MetaMask is locked.
true
if MetaMask is locked, false
if MetaMask is unlocked.
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()
}
}
Gets a deterministic 256-bit entropy value, specific to the Snap and the user's account. You can use this entropy to generate a private key, or any other value that requires a high level of randomness. Other Snaps can't access this entropy, and it changes if the user's secret recovery phrase changes.
You can optionally specify a salt to generate different entropy for different purposes. Using a salt results in entropy unrelated to the entropy generated without a salt.
This value is deterministic: it's always the same for the same Snap, user account, and salt.
An object containing:
version
- The number1
. This is reserved for future use.salt
(optional) - An arbitrary string to be used as a salt for the entropy. This can be used to generate different entropy for different purposes.
The entropy as a hexadecimal string.
"initialPermissions": {
"snap_getEntropy": {}
}
const entropy = await snap.request({
method: "snap_getEntropy",
params: {
version: 1,
salt: "foo", // Optional.
},
})
// "0x..."
console.log(entropy)
Gets a static file's content in UTF-8, Base64, or hexadecimal. The file must be specified in the Snap's manifest file.
An object containing:
path
- The path to the file, relative to the Snap's package directory (that is, one level abovesrc
).encoding
(optional) - One ofutf8
,base64
, orhex
. The default isbase64
.
The file content as a string in the requested encoding.
"source": {
"shasum": "xxx",
"location": {
// ...
},
"files": [
"./files/myfile.bin"
]
}
const contents = await snap.request({
method: "snap_getFile",
params: {
path: "./files/myfile.bin",
encoding: "hex",
},
})
// "0x..."
console.log(contents)
Gets the user's locale setting. You can use this method to localize text in your snap.
:::warning
This method is deprecated.
Use snap_getPreferences
instead.
:::
The user's locale setting as a language code.
import { Box, Text } from "@metamask/snaps-sdk/jsx";
const locale = await snap.request({ method: "snap_getLocale" });
let greeting = "Hello";
if(locale === "es") {
greeting = "Hola";
}
await snap.request({
method: "snap_dialog",
params: {
type: "alert",
content: (
<Box>
<Text>{greeting}</Text>
</Box>
),
},
});
import { panel, text } from "@metamask/snaps-sdk";
const locale = await snap.request({ method: "snap_getLocale" })
let greeting = "Hello"
if (locale === "es") {
greeting = "Hola"
}
await snap.request({
method: "snap_dialog",
params: {
type: "alert",
content: panel([text(greeting)]),
},
})
Gets the user's preferences.
An object containing the user's preferences:
locale
- The user's locale setting as a language code.currency
- The user's preferred fiat currency code.
import { Box, Text } from "@metamask/snaps-sdk/jsx";
const { locale } = await snap.request({ method: "snap_getPreferences" });
let greeting = "Hello";
if(locale === "es") {
greeting = "Hola";
}
await snap.request({
method: "snap_dialog",
params: {
type: "alert",
content: (
<Box>
<Text>{greeting}</Text>
</Box>
),
},
});
Manages account management Snap accounts. This method is organized into multiple sub-methods which each take their own parameters:
Creates a new Snap account.
:::note
The Snap is responsible for maintaining its own record of accounts.
This can be done using snap_manageState
.
:::
account
- An account object.
null
import { Keyring, KeyringAccount } from "@metamask/keyring-api"
class MyKeyring implements Keyring {
// Other methods.
async createAccount(
name: string,
options: Record<string, Json> | null = null
): Promise<KeyringAccount> {
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
}
}
Updates an existing Snap account.
:::note
The Snap is responsible for maintaining its own record of accounts.
This can be done using snap_manageState
.
:::
account
- An account object.
null
import { Keyring, KeyringAccount } from "@metamask/keyring-api"
class MyKeyring implements Keyring {
// Other methods.
async updateAccount(account: KeyringAccount): Promise<void> {
// Store the new account details in state.
await snap.request({
method: "snap_manageAccounts",
params: {
method: "updateAccount",
params: { account },
},
})
}
}
Deletes a Snap account.
:::note
The Snap is responsible for maintaining its own record of accounts.
This can be done using snap_manageState
.
:::
id
- The ID of the account to be deleted.
null
import { Keyring } from "@metamask/keyring-api"
class MyKeyring implements Keyring {
// Other methods.
async deleteAccount(id: string): Promise<void> {
// Delete the account from state.
await snap.request({
method: "snap_manageAccounts",
params: {
method: "deleteAccount",
params: { id },
},
})
}
}
Lists the calling Snap's accounts that are known to MetaMask. This method does not call back to the Snap. Instead, the Snap can use it to check whether there's a discrepancy between the Snap's internal state of accounts and the state known to MetaMask.
An array of account objects.
import { Keyring, KeyringAccount } from "@metamask/keyring-api";
class MyKeyring implements Keyring {
// Other methods.
async checkIfAccountsInSync(): Promise<boolean> {
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.
}
}
Finalizes a signing request.
This is usually called as part of the
keyring_approveRequest
method.
id
- The ID of the request to finalize.result
- The result that should be returned to the original JSON-RPC caller.
null
import { Keyring } from "@metamask/keyring-api"
import { Json } from "@metamask/utils"
class MyKeyring implements Keyring {
// Other methods.
async approveRequest(id: string, result?: Json): Promise<void> {
// Do any Snap-side logic to finish approving the request.
await snap.request({
method: "snap_manageAccounts",
params: {
method: "submitResponse",
params: { id, result },
},
})
}
}
Allows the Snap to persist up to 100 MB of data to disk and retrieve it at will.
By default, the data is automatically encrypted using a Snap-specific key and automatically
decrypted when retrieved.
You can set encrypted
to false
to use unencrypted storage.
An object containing:
operation
- The state operation to perform ("clear"
,"get"
, or"update"
).newState
- The value to update state with if the operation is"update"
, and nothing otherwise.encrypted
(optional) - Indicates whether the Snap will encrypt the data. The default istrue
.
The value stored in state if the operation is get
, and null
otherwise.
// Persist some data.
await snap.request({
method: "snap_manageState",
params: {
operation: "update",
newState: { hello: "world" },
},
})
// At a later time, get the stored data.
const persistedData = await snap.request({
method: "snap_manageState",
params: { operation: "get" },
})
console.log(persistedData)
// { hello: "world" }
// If there's no need to store data anymore, clear it out.
await snap.request({
method: "snap_manageState",
params: {
operation: "clear",
},
})
Displays a notification in MetaMask or natively in the OS.
Snaps can trigger a short (up to 80 characters) notification message for actionable or time sensitive information.
inApp
notifications can also include an optional expanded view.
The expanded view has a title, content, and optional footer link shown when a user clicks on the notification.
An object containing the contents of the notification:
type
- The notification type ("inApp"
or"native"
). We recommend usingtype: "inApp"
because there's no guarantee that native notifications are displayed to the user.message
- A message to show in the notification.- Optional expanded view parameters
title
- The title of the expanded view, shown when a user expands the notification.content
- A custom Snap UI shown in the expanded viewfooterLink
(optional) - A custom footer object withtext
andhref
, displayed as an action button in the footer of the expanded view.
:::caution
Expanded view can only be used with notifications of type inApp
.
Expanded view must have at least a title
and content
.
:::
await snap.request({
method: "snap_notify",
params: {
type: "inApp",
message: "Hello, world!",
},
})
await snap.request({
method: "snap_notify",
params: {
type: "inApp",
message: "Hello, world!",
title: "Hello from a Snap",
content: (
<Box>
<Heading>Hello, world!</Heading>
<Text>This is a notification sent from a Snap.</Text>
</Box>
),
footerLink: {
href: "https://snaps.metamask.io",
text: "Find more Snaps",
},
},
})
await snap.request({
method: "snap_notify",
params: {
type: "native",
message: "Hello, world!",
},
})
The following methods are used in interactive UI. These methods do not require requesting permission in the Snap manifest file.
Creates an interactive interface for use in interactive UI.
An object containing:
ui
- The custom UI to create.context
(optional) - A custom context object that will be passed toonUserInput
when the user interacts with the interface.
The interface's ID to be used in snap_dialog
, returned from
onTransaction
or onHomePage
.
const interfaceId = await snap.request({
method: "snap_createInterface",
params: {
ui: (
<Box>
<Heading>Interactive interface</Heading>
<Button name="interactive-button">Click me</Button>
</Box>
)
},
})
await snap.request({
method: "snap_dialog",
params: {
type: "Alert",
id: interfaceId,
},
})
Gets the state of an interactive interface by its ID. For use in interactive UI.
id
- The ID of the interface.
An object where each top-level property can be one of the following:
- The
name
of aninput
with its current value. - The
name
of aform
, with a nested object containing the current values of allinputs
in the form.
const interfaceId = await snap.request({
method: "snap_createInterface",
params: {
ui: (
<Box>
<Heading>Interactive UI Example Snap</Heading>
<Input name="top-level-input" placeholder="Enter something"/>
<Form name="example-form">
<Input name="nested-input" placeholder="Enter something"/>
<Button type="submit">Submit</Button>
</Form>
</Box>
)
},
})
const state = await snap.request({
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"
}
}
*/
Gets the context of an interactive interface by its ID. For use in interactive UI.
id
- The ID of the interface.
An object of type InterfaceContext
if a custom context object was passed when creating or updating the interface, or null
.
const interfaceId = await snap.request({
method: "snap_createInterface",
params: {
ui: (
<Box>
<Heading>Hello, world!</Heading>
<Text>Welcome to my Snap homepage!</Text>
</Box>
),
context: {
key: "value"
}
},
})
const context = await snap.request({
method: "snap_getInterfaceContext",
params: {
id: interfaceId,
},
})
console.log(context)
/*
{
"key": "value"
}
*/
Resolves an interactive interface. For use in custom dialogs.
An object containing:
id
- The ID of the interface to be resolved.result
- The result to return to the interface's caller.
For a full example of how to use snap_resolveInterface
, see the custom dialogs documentation.
Updates an interactive interface. For use in interactive UI.
An object containing:
id
- The ID of the interface to be updated, usually received in theonUserInput
entry point.ui
- The custom UI to create.context
- (Optional) A custom context object that will be passed toonUserInput
when the user interacts with the interface. Passing this parameter will update the context object for the interface.
export function onUserInput({ id, event }) {
console.log("Received input event", event);
await snap.request({
method: "snap_updateInterface",
params: {
id,
ui: (
<Box>
<Heading>New interface</Heading>
<Text>This interface has been updated</Text>
</Box>
)
},
});
};