Autotask Tutorial 1: Get Started with Autotasks in OpenZeppelin Defender

This tutorial provides an introduction into Defender Autotasks.

What Is An Autotask?

An Autotask is an environment available via Defender where you can execute a bit of Javascript code based on a schedule or triggered by some set of conditions. Check out the first section of the documentation for an overview on Autotasks and how they relate to other Defender components.

Behind the Scenes of the Autotask environment

Example Autotasks:

Create a Hello World Autotask

This walkthrough provides a hands-on introduction into the moving parts involved in setting up a Defender Autotask.

Setup

The Autotask you'll be creating will make use of a Relayer to make ethers.js JSON-RPC calls.

Create a new Relayer
Select Relay from the left and then select Create Relayer. Give the Relayer a name and select Goerli for the network.

Hello World - (Using Web Interface)

In Defender, each of the main components are listed on the left of the screen.

Select Autotask -> New Autotask

Give the Autotask a name and select Webhook so that it can be triggered via a request sent to the Autotask's endpoint.

Select the Relayer you just created so that the Autotask can connect to it as a provider and make network queries using Ethers.js.

An Autotask is a bit of serverless code that needs to export a handler. The handler is what gets invoked each time the Autotask is triggered.

Supply the following code in the Autotask:

const { KeyValueStoreClient } = require('defender-kvstore-client')
const ethers = require('ethers')
const {
  DefenderRelaySigner,
  DefenderRelayProvider,
} = require('defender-relay-client/lib/ethers')

async function handler(event) {
  const store = new KeyValueStoreClient(event)
  const provider = new DefenderRelayProvider(event)
  const {userName} = event.request.body;
  const block = await provider.getBlockNumber();
  const lastRunBlockNumber = await store.get('lastRunBlockNumber')
  let msg = (lastRunBlockNumber) ? `This Autotask was last triggered on block 
     ${lastRunBlockNumber}` : 'This is the first time this Autotask has been triggered'

  await store.put('lastRunBlockNumber', block.toString())

  return `Hello ${userName}! Current block: ${block}. ${msg}`;
}

module.exports = {
  handler,
}



The Key-value data store package allows you to persist data storage across different Autotask runs.

On the next screen, copy the Webhook URI.

Open Postman (or similar) and create a new POST request. Paste the Autotask's endpoint. Under the Body tab, send the following as raw/JSON:

{
    "name": "Satoshi"
}

Run the request! You'll see the greeting in the body's result.

Congratulations on successfully creating and triggering an Autotask! Next, you'll use the client package (rather than the web interface) to create an Autotask.

Hello World - (Using defender-autotask-client)

The Defender client packages allows you to create and manage the various Defender components via API using your favorite code editor.

Create a new folder and initialize a package.json:

$ mkdir autotasks && cd autotasks && yarn init -y

Install the Defender Autotask Client and necessary npm packages:

$ yarn add defender-autotask-client defender-relay-client defender-kvstore-client dotenv

The defender-client package allows you full CRUD functionality with Autotasks.

Create a gitignored file to store environment variables:

$ touch .env

Supply your Defender Team API key and secret in this file:

API_KEY=
API_SECRET=

Create a new index.js file for your Autotask code.

$ mkdir autotasks && touch autotasks/index.js

When using the client package, Defender expects the Autotask code to be in an index.js file.

In index.js, supply the same Autotask code as before.

Get the relayer's ID

The Autotask knows which relayer is connected to it by having the Relayer ID specified.

Using the web UI, it was only a matter of selecting the Relayer. Using defender-client package, you'll need to specify the Relayer using its ID.

Using the defender-relay-client package you can run a simple query to list all relayers associated with your Defender account.

$ mkdir scripts && touch scripts/getRelayerId.js

Add the following code and run the script:

const { RelayClient } = require('defender-relay-client');

async function run() {
  const { API_KEY: apiKey, API_SECRET: apiSecret } = process.env;
  const relayClient = new RelayClient({ apiKey, apiSecret });
  console.log(await relayClient.list());
}

run().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Copy the relayerId value of whichever Relayer you would like the Autotask to be connected to. You'll supply this value in the Autotask creation script.

Next, create the script to deploy the code:

$ mkdir scripts && touch scripts/createAutotask.js

Add the following code:

const { AutotaskClient } = require('defender-autotask-client')

async function main() {
  require('dotenv').config()
  const credentials = {
    apiKey: process.env.API_KEY,
    apiSecret: process.env.API_SECRET,
  }
  const autotaskClient = new AutotaskClient(credentials)

  const params = {
    name: 'Hello World 2',
    encodedZippedCode: await autotaskClient.getEncodedZippedCodeFromFolder(
      './autotasks'
    ),
    trigger: {
      type: 'webhook',
    },
    paused: false,
    relayerId: '3f12191a-26a3-44ca-a3c9-ab7b57a97b8e',
  }

  const createdAutotask = await autotaskClient.create(params)
  console.log('Created Autotask with ID: ', createdAutotask.autotaskId)

}

if (require.main === module) {
  main()
    .then(() => process.exit(0))
    .catch((error) => {
      console.error(error)
      process.exit(1)
    })
}

Run it with node scripts/createAutotask.js

Open Defender and refresh the Autotasks dashboard. Copy this Autotask's webhook, supply it to Postman and trigger the Autotask as before.

Note that because Autotasks use the same key-value store, you will see the stored value from the Autotask created previously via the UI.

Congratulations on taking your first steps into the world of Defender Autotasks!