npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@mountainpath9/overlord

v0.14.0

Published

A typescript library to support contract automation tasks in the overlord framework.

Downloads

151

Readme

What is it?

A typescript library to support contract automation tasks in the overlord framework.

Usage

A instance of the TaskRunner class manages a suite of tasks. It's expected that it runs under nodejs. The structure is typically:

import { createTaskRunner } from "@mountainpath9/overlord";

async function main() {
  const runner = createTaskRunner();

  // specify tasks here
  
  runner.main();
}

main();

The above program will fetch configuration from the OVL_TASK_RUNNER_CONFIG environment variable and then manage the specified tasks.

Scheduled tasks

Scheduled tasks run according to a cron style type schedule. An example:

  runner.addPeriodicTask({
    id: 'heatbeat',
    cronSchedule: '*/10 * * * * *',
    action: async (ctx, date) => {
      ctx.logger.info(`tick at ${date.toISOString()}...`);
      return taskSuccess();
    },
  });

The cron syntax is as per the cron-parser package. The ctx parameter provides task specific context, including a winston implemented logger as above. The date parameter provides the scheduled time of the task.

.addPeriodicTask permits a allowConcurrent parameter. By default, subsequent runs of a task will be skipped when a previous run is still in progress. If allowConcurrent is present and true, then subsequent runs will run concurrently with any previous ones.

Webhook tasks

Webhook tasks are triggered via an HTTP post request. An example:

  runner.addWebhookTask({
    id: 'some-webhook',
    action: async (ctx, koaCtx) => {
      ctx.logger.info(`webhook from ${koaCtx.ip}`);
      return taskSuccess();
    },
  });

The koaCtx provides details of the web request. It can be used for authorisation, and also to obtain the request body for request specific parameters.

On Boot task

"On boot" tasks are run a single time when the task runner starts up:

  runner.addOnBootTask({
    id: 'onBootTask1',
    action: async (ctx) => {
      ctx.logger.info("onBoot task 1");
      return taskSuccess();
    },
  });

Chain Event tasks

Chain event tasks are triggered whenever an event on an EVM blockchain is generated that matches a provided filter:

import { Contract } from "ethers";
...
  const chainId = 1;
  const daiContractAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F'; 
  const provider = await runner.getProvider(chainId);
  let abi = [ 
    "event Transfer(address indexed from, address indexed to, uint value)" 
  ];
  let contract = new Contract(daiContractAddress, abi, provider);
  const filter = contract.filters.Transfer();

  runner.addChainEventTask({
    id:'alert_dai_token_transfer',
    chainId,
    filters: [filter],
    action: async (ctx, evmlog) => {
      const args = contract.interface.parseLog(evmlog).args;
      ctx.logger.info(`dai transfer: from=${args.from} to=${args.to} value=${args.value}`);
      return taskSuccess();
    }
  });

The above example uses ethersjs untyped event decoding. It's possible to use TypeChain to improve static typing rigor.

Task context

As mentioned above, a variety of contextual information is available to tasks via the ctx parameter. This value has type

export interface TaskContext {
  logger: Logger;

  getProvider(chainId: number): Promise<Provider>;
  getSigner(provider: Provider, signerId: string): Promise<Signer>;

  kvGet(key: string): Promise<Json | undefined>;
  kvSet(key: string, value: Json): Promise<void>;
  kvClear(key: string): Promise<void>;
  config: ConfigAccess;
};

export interface ConfigAccess {
  get(configId: string): Promise<Json | undefined>;

  getString(configId: string): Promise<string | undefined>;
  getNumber(configId: string): Promise<number | undefined>;
  getBoolean(configId: string): Promise<boolean | undefined>;

  requireString(configId: string): Promise<string>;
  requireNumber(configId: string): Promise<number>;
  requireBoolean(configId: string): Promise<boolean>;
}

The KV store has string keys, and the values are arbitrary json. Here is a stateful task:

  runner.addPeriodicTask({
    id: 'heatbeat',
    cronSchedule: '*/10 * * * * *',
    action: async (ctx) => {
      const toggle = !!await ctx.kvGet('toggle');
      ctx.logger.info(toggle ? "tick..." : `tock...`);
      await ctx.kvSet('toggle', !toggle);
      return taskSuccess();
    },
  });

When running under the overlord framework, the kv store is persistent, with keys shared between task runners configured in the same tenant.

The overlord framework can manage secrets on behalf of tasks. These must be preconfigured, and are accessible via the getSecret() method.

Finally, when configured, tasks have access to EVM providers and signers.

Task Results

A succesfull task should return taskSuccess() which will cause it to be recorded in the overlord dashboard. If it returns taskSuccessSilent() then a dashboard record will not be created.

The framework will catch and log all exceptions thrown by tasks. For global custom notifications, a specific handler may be provided

  runner.setTaskExceptionHandler( async (ctx: TaskContext, te:TaskException) => {
    // perform existing overlord logging
    await logTaskException(ctx, te);
    
    // then custom notifications code ...
  });

Development

The overlord framework expects tasks runners to be packaged as nodejs docker containers. But for local testing, it is convenient to run task runners directly. This can be done by compiling the typescript, setting the OVL_TASK_RUNNER_CONFIG environment variable, and running the generated javascript. With an appropriate package.json this can look like:

export OVL_TASK_RUNNER_CONFIG='{
  "label":"demo_tasks",
  "http_port":8111,
  "manager":{
    "local" :{
        "providers":[
          {
            "chain_id":80001,
            "rpc_url":"https://rpc.ankr.com/polygon_mumbai"
          }
        ],
        "vars": {
          "test_secret1":"XXX",
          "test_secret2":"true"
        },
        "signers":[
          {
            "chain_id":80001,
            "signer_id": "demo_tasks_signer",
            "kind": {
                "private_key": "TESTPRIVATEKEY"
            }
          }
        ]
    }
  }
}'
yarn
yarn tsc
node dist/main.js

If desired one can run against a local network fork, by using the appropriate rpc_url.

When run locally, all of the task types will run as requested. To manually trigger tasks it's useful to have webhook tasks setup, and then trigger them with curl:

curl  -X POST -D '{}' http://localhost:8111/webhooks/demo-test-webhook

To build and publish the overlord library itself:

pnpm install
pnpm build
(cd dist; npm publish --access=public)