Snaps entry points
Snaps can expose the following entry points.
onCronjob
To run cron jobs for the user, a Snap must expose the onCronjob
entry point.
MetaMask calls the onCronjob
handler method at the specified schedule with the requests defined in
the endowment:cronjob
permission.
For MetaMask to call the Snap's onCronjob
method, you must request the
endowment:cronjob
permission.
Parameters
An object containing an RPC request specified in the endowment:cronjob
permission.
Example
- TypeScript
- JavaScript
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.");
}
};
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.");
}
};
onHomePage
To display a home page within MetaMask, a Snap must expose
the onHomePage
entry point.
MetaMask calls the onHomePage
handler method when the user selects the Snap name in the Snaps menu.
For MetaMask to call the Snap's onHomePage
method, you must request the
endowment:page-home
permission.
Parameters
None.
Returns
One of the following:
- A
content
object displayed using custom UI. - An
id
returned bysnap_createInterface
for interactive UI.
Example
- TypeScript
- JavaScript
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!"),
]),
};
};
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!"),
]),
};
};
onInstall
To implement a lifecycle hook that runs an action upon
installation, a Snap must expose the onInstall
entry point.
MetaMask calls the onInstall
handler method after the Snap is installed successfully.
For MetaMask to call the Snap's onInstall
method, you must request the
endowment:lifecycle-hooks
permission.
Parameters
None.
Example
- TypeScript
- JavaScript
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).",
),
]),
},
});
};
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).",
),
]),
},
});
};
onKeyringRequest
To implement the Account Management API to integrate
custom EVM accounts, an account management Snap must
expose the onKeyringRequest
entry point.
Whenever the Snap receives an Account Management API request, MetaMask calls the onKeyringRequest
handler method.
For MetaMask to call the Snap's onKeyringRequest
method, you must request the
endowment:keyring
permission.
Parameters
An object containing:
origin
- The origin as a string.request
- The JSON-RPC request.
Returns
A promise containing the return of the implemented method.
Example
- TypeScript
- JavaScript
export const onKeyringRequest: OnKeyringRequestHandler = async ({
origin,
request,
}) => {
// Any custom logic or extra security checks here.
return handleKeyringRequest(keyring, request);
};
module.exports.onKeyringRequest = async ({ origin, request }) => {
// Any custom logic or extra security checks here.
return handleKeyringRequest(keyring, request);
};
onNameLookup
To provide custom name resolution, a Snap must export onNameLookup
.
Whenever a user types in the send field, MetaMask calls this method.
MetaMask passes the user input to the onNameLookup
handler method.
For MetaMask to call the Snap's onNameLookup
method, you must request the
endowment:name-lookup
permission.
Parameters
An object containing:
chainId
- The CAIP-2 chain ID.address
ordomain
- One of these parameters is defined, and the other is undefined.
Example
- TypeScript
- JavaScript
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;
};
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;
};
onRpcRequest
To implement a custom JSON-RPC API to communicate with
dapps and other Snaps, a Snap must expose the onRpcRequest
entry point.
Whenever the Snap receives a JSON-RPC request, MetaMask calls the onRpcRequest
handler method.
For MetaMask to call the Snap's onRpcRequest
method, you must request the
endowment:rpc
permission.
Parameters
An object containing:
origin
- The origin as a string.request
- The JSON-RPC request.
Returns
A promise containing the return of the implemented method.
Example
- TypeScript
- JavaScript
import type { OnRpcRequestHandler } from "@metamask/snaps-sdk";
export const onRpcRequest: OnRpcRequestHandler = async ({
origin,
request,
}) => {
switch (request.method) {
case "hello":
return "world!";
default:
throw new Error("Method not found.");
}
};
module.exports.onRpcRequest = async ({ origin, request }) => {
switch (request.method) {
case "hello":
return "world!";
default:
throw new Error("Method not found.");
}
};
onSignature
To provide signature insights before a user signs a message, a
Snap must expose the onSignature
entry point.
Whenever a signing method is called, such as personal_sign
or
eth_signTypedData_v4
, MetaMask passes the raw unsigned signature payload to the onSignature
handler method.
For MetaMask to call the Snap's onSignature
method, you must request the
endowment:signature-insight
permission.
Parameters
An object containing:
signature
- The raw signature payload.signatureOrigin
- The signature origin ifallowSignatureOrigin
is set totrue
.
Returns
- An optional
severity
property that, if present, must be set toSeverityLevel.Critical
. - A
content
object displayed using custom UI after the user selects the Sign button. Due to current limitations of MetaMask's signature confirmation UI, the content will only be displayed if theseverity
property is present and set toSeverityLevel.Critical
.
Example
- TypeScript
- JavaScript
import type { OnSignatureHandler, SeverityLevel } from "@metamask/snaps-sdk";
import { panel, heading, text } from "@metamask/snaps-sdk";
export const onSignature: OnSignatureHandler = async ({
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,
};
};
import { SeverityLevel } from "@metamask/snaps-sdk";
import { panel, heading, text } from "@metamask/snaps-sdk";
module.exports.onSignature = async ({
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,
};
};
onTransaction
To provide transaction insights before a user signs a
transaction, a Snap must expose the onTransaction
entry point.
When a user submits a transaction in the MetaMask extension, MetaMask calls the onTransaction
handler method.
MetaMask passes the raw unsigned transaction payload to onTransaction
.
For MetaMask to call the Snap's onTransaction
method, you must request the
endowment:transaction-insight
permission.
Parameters
An object containing:
transaction
- The raw transaction payload.chainId
- The CAIP-2 chain ID.transactionOrigin
- The transaction origin ifallowTransactionOrigin
is set totrue
.
Returns
- An optional
severity
property that, if present, must be set to"critical"
. This feature is only available in Flask. - One of the following:
- A
content
object displayed using custom UI, alongside the confirmation for the transaction thatonTransaction
was called with. - An
id
returned bysnap_createInterface
for interactive UI.
- A
Example
- TypeScript
- JavaScript
import type { OnTransactionHandler } from "@metamask/snaps-sdk";
import { panel, heading, text } from "@metamask/snaps-sdk";
export const onTransaction: OnTransactionHandler = async ({
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))),
]),
};
};
import { panel, heading, text } from "@metamask/snaps-sdk";
module.exports.onTransaction = async ({
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))),
]),
};
};
onUpdate
To implement a lifecycle hook that runs an action upon update, a
Snap must expose the onUpdate
entry point.
MetaMask calls the onUpdate
handler method after the Snap is updated successfully.
For MetaMask to call the Snap's onUpdate
method, you must request the
endowment:lifecycle-hooks
permission.
Parameters
None.
Example
- TypeScript
- JavaScript
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."
),
]),
},
});
};
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."
),
]),
},
});
};
onUserInput
To respond to interactive UI events, a Snap must export onUserInput
.
Parameters
id
- The ID of the interface being acted on.event
- An event object containing:type
- The type of the event. Possible values areButtonClickEvent
,FormSubmitEvent
, orInputChangeEvent
. These enums are exported from the@metamask/snaps-sdk
module.name
- The name of the component that fired the event. Optional when the event type isButtonClickEvent
.value
- When the event type isFormSubmitEvent
, the values in the form as an object.
Example
- TypeScript
- JavaScript
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);
}
};
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);
}
};