Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Document Snaps cron jobs feature #1271

Merged
merged 4 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ of the [MetaMask developer page](https://metamask.io/developer/).

## April 2024

- Documented [Snaps cron jobs](/snaps/features/cron-jobs).
([#1271](https://github.com/MetaMask/metamask-docs/pull/1271))
- Updated [how to connect to MetaMask](/wallet/how-to/connect) with vanilla TypeScript and React
TypeScript instructions.
([#1247](https://github.com/MetaMask/metamask-docs/pull/1247))
Expand Down
87 changes: 87 additions & 0 deletions snaps/features/cron-jobs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
description: Schedule periodic actions for your users.
sidebar_position: 1
---

# Cron jobs

You can schedule actions to run periodically at fixed times or intervals, also known as "cron jobs."
For example, you can display a dialog or notification in MetaMask at a specific time each day.

## Steps

### 1. Configure a cron job

To configure a cron job, request the [`endowment:cronjob`](../reference/permissions.md#endowmentcronjob)
permission, specifying one or more cron jobs in the `jobs` array.
Define each job with a [cron expression](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm)
and a request object, which MetaMask sends to the Snap's cron job handler when the job is executed.

For example, to configure a job that executes every minute, add the following to your Snap's manifest file:

```json title="snap.manifest.json"
"initialPermissions": {
"endowment:cronjob": {
"jobs": [
{
"expression": "* * * * *",
"request": {
"method": "execute"
}
}
]
}
}
```

### 2. Implement a cron job handler

Expose an [`onCronjob`](../reference/entry-points.md#oncronjob) entry point, which is triggered at
the specified schedule with the requests defined in the `endowment:cronjob` permission.
The following example handles the `execute` method specified in the previous example:

```typescript title="index.ts"
import type { OnCronjobHandler } from "@metamask/snaps-sdk";

export const onCronjob: OnCronjobHandler = async ({ request }) => {
switch (request.method) {
case "execute":
// Cron jobs can execute any method that is available to the Snap.
return snap.request({
method: "snap_dialog",
params: {
type: "alert",
content: panel([
heading("Cron job"),
text("This dialog was triggered by a cron job."),
]),
},
});

default:
throw new Error("Method not found.");
}
};
```

:::tip Access data from cron jobs
When accessing encrypted data from cron jobs using
[`snap_manageState`](../reference/snaps-api.md#snap_managestate), MetaMask requires the user to
enter their password if the wallet is locked.
This interaction can be confusing to the user, since the Snap accesses the data in the background
without the user being aware.

If the cron job requires access to encrypted state, use
[`snap_getClientStatus`](../reference/snaps-api.md#snap_getclientstatus) to ensure that MetaMask is
unlocked before accessing state.
This will prevent an unexpected password request, improving the user's experience.

If the cron job does not require access to sensitive data, store that data in
unencrypted state by setting `encrypted` to `false` when using
[`snap_manageState`](../reference/snaps-api.md#snap_managestate).
:::

## Example

See the [`@metamask/cronjob-example-snap`](https://github.com/MetaMask/snaps/tree/main/packages/examples/packages/cronjobs)
package for a full example of implementing cron jobs.
2 changes: 1 addition & 1 deletion snaps/features/custom-evm-accounts/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Connect to custom EVM accounts using the Keyring API.
sidebar_position: 4
sidebar_position: 2
tags:
- Keyring API
---
Expand Down
2 changes: 1 addition & 1 deletion snaps/features/custom-name-resolution.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Resolve names to addresses and vice versa.
sidebar_position: 6
sidebar_position: 3
sidebar_custom_props:
flask_only: true
---
Expand Down
2 changes: 1 addition & 1 deletion snaps/features/custom-ui/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Display custom user interface components.
sidebar_position: 1
sidebar_position: 4
---

# Custom UI
Expand Down
2 changes: 1 addition & 1 deletion snaps/features/localization.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Display your Snap's UI and metadata in the user's language.
sidebar_position: 2
sidebar_position: 5
---

# Localization
Expand Down
2 changes: 1 addition & 1 deletion snaps/features/non-evm-networks.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Manage users' non-EVM accounts and assets.
sidebar_position: 3
sidebar_position: 6
---

# Non-EVM networks
Expand Down
2 changes: 1 addition & 1 deletion snaps/features/static-files.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Include and retrieve static files in the Snap bundle.
sidebar_position: 5
sidebar_position: 8
---

# Static files
Expand Down
2 changes: 1 addition & 1 deletion snaps/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ The following Snaps features are available in the stable version of MetaMask:
},
{
icon: require("./assets/features/cronjob.png").default,
href: "reference/entry-points#oncronjob",
href: "features/cron-jobs",
title: "Cron jobs",
description: "Schedule periodic actions for your users."
},
Expand Down
23 changes: 4 additions & 19 deletions snaps/reference/entry-points.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,15 @@ Snaps can expose the following entry points.

## `onCronjob`

To run periodic actions for the user (cron jobs), a Snap must expose the `onCronjob` entry point.
MetaMask calls the `onCronjob` handler method at the specified times with the specified payloads
defined in the [`endowment:cronjob`](permissions.md#endowmentcronjob) permission.
To run [cron jobs](../features/cron-jobs.md) 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`](permissions.md#endowmentcronjob) permission.

:::note
For MetaMask to call the Snap's `onCronjob` method, you must request the
[`endowment:cronjob`](permissions.md#endowmentcronjob) permission.
:::

:::info Access data from cron jobs
When accessing encrypted data from cron jobs using [`snap_manageState`](../reference/snaps-api.md#snap_managestate),
MetaMask requires the user to enter their password if the wallet is locked.
This interaction can be confusing to the user, since the Snap accesses the data in the background
without the user being aware.

If your Snap's cron job does not need to access sensitive data, store that data in unencrypted state
by setting `encrypted` to `false` when using [`snap_manageState`](../reference/snaps-api.md#snap_managestate).
:::

If the cron job's logic requires access to encrypted state, you can use
[`snap_getClientStatus`](../reference/snaps-api.md#snap_getclientstatus) to ensure that MetaMask is
unlocked before accessing state.
This will prevent an unexpected password request popup, improving the user's experience.

#### Parameters

An object containing an RPC request specified in the `endowment:cronjob` permission.
Expand All @@ -52,7 +37,7 @@ export const onCronjob: OnCronjobHandler = async ({ request }) => {
switch (request.method) {
case "exampleMethodOne":
return snap.request({
method: 'snap_notify',
method: "snap_notify",
params: {
type: "inApp",
message: "Hello, world!",
Expand Down
9 changes: 8 additions & 1 deletion snaps/reference/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,17 @@ manifest file:

### `endowment:cronjob`

To run periodic actions for the user (cron jobs), a Snap must request the `endowment:cronjob` permission.
To run [cron jobs](../features/cron-jobs.md) for the user, a Snap must request the `endowment:cronjob` permission.
This permission allows the Snap to specify cron jobs that trigger the
[`onCronjob`](../reference/entry-points.md#oncronjob) entry point.

This permission takes an object with an array of `jobs`, each containing two parameters:

- `expression` - A [cron expression](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm)
that defines the schedule of the job.
- `request` - A JSON-RPC request object that will be sent to the Snap's `onCronjob` entry point when
the job is executed.

:::tip
You can modify the cron job's execution limit using [Snap-defined timeouts](#snap-defined-timeouts).
:::
Expand Down
Loading