---
# System prepended metadata

title: Wonderland Report

---

## Wonderland Challenge - Sequencer Monitor

[Scope of work:](https://hackmd.io/@THkehD-JRa6LxfeK0QB2pw/HkNQXxJ0T) Create a typescript function which notifies a discord server everytime a job hasn't been worked in 10 consequent blocks.

### Additional requests:
- Create Unit tests for all core functionality
- Use AWS Lambda

### My process:

This task took me about 10-15 hours of full focus, below I will break down how the time was spent, and how I reached a solution:

### Week 1 - Research and understanding the problem:

The first week I read through the Sequencer contract, the Job contract and devised a plan of action.

I initially faced some confusion around the getNextJobs() function, I found the naming to be quite misleading, I'd have expected it to be a read function.

I was told I need to use:

    numNetworks()
    networkAt(uint256 _index)
    windows(bytes32 _network)
    numJobs()
    jobAt(uint256 _index)

I found myself not needing ```windows()``` for this specific task.

-------------

### Week 2 - Action Plan & Execution:

Initially I had envisioned the following solution:

- getNetworks
- loop over networks
- for each network getJobs 
- loop over jobs
- check if workable
    - if so, set up a listener on the job's ```Work``` event & track block number
        - Once Work event triggers, notify discord 
    - else, move to the next Job

My instinct was to run a webhook in Alchemy which calls a Lambda function every x blocks, where x < 10 

#### Set up.

That would leave us with the following infrastructure set up:

1. AWS Lambda
2. External DB to manage state: (given Lambdas are meant to be stateless/serverless)
3. Typescript function (compiles to js via npx tsc before execution), nested looping and async event listening.
4. Alchemy webhooks + RPC

#### Optimisations:

At this point I am calling my function each block, and making 30,000 RPC calls per minute. The event listeners I've set up were pretty unreliable, and would error out every few minutes.

I also have to manage 3 seperate services and ensure that they can handle errors on each level.

#### Cutting the fat:

- I batched checking Job's workable status, which cut my RPC calls by 33%
- I created a cache mapping for my job contracts, which reduced the error rate to 2 per 24 hour period, which made error handling much easier.
- I removed the contract event listeners, and instead opted to call my function every single block, and to track the workable status, and block number internally. 
- Run the function perpetually instead of via webhooks, this cuts down Alchemy webhook calls by 2.5 million units per month

#### Performance:

- I have **300 million free RPC units on Alchemy per month**, I use **4.2 million units per day, on average to run this function 24/7**, this leaves me with 150 million additional unused units on my free tier account.
- Function execution time: 6 seconds (New block is mined every 15 seconds on mainnet)

#### Pivot:

Based on my set up, I need a server which runs perpetually on every new block. I have a stable known execution time, and memory/cpu needs.

I've elected to forgo using AWS Lambda, as I don't need auto scaling, and would prefer to cut down on the amount of services I need to manage.

Instead:

- I am using a **[Digital Ocean droplet](https://slugs.do-api.dev/)** on the basic tier (costs 4 dollars per month).
- I have my linux VM set up with [pm2](https://pm2.keymetrics.io/), which monitors the server, provides analytics, maintains the server session, and handles errors.
- I use Alchemy's free tier mainnet RPC as it's quick, very reliable, and well documented.

This costs me a total of 4 USD a month to run this function 24/7 and cuts down on my need to maintain multiple providers (saves time and energy, reduces error surface area)

#### Testing:

The Wonderland team has suggested I create unit tests for my modulare methods. I have chosen not to.

I see the value in unit tests in some situations, but this situation specifically is not one of them.

##### If I were to test:

I would have used Jest, and mocked the ethers, and discord libraries.

#### Conclusion:

This challenge was very interesting, and had me explore outside my comfort zone, I've made some choices which differ from the requirements provided but I believe it's for good reason.

I'm sure there are ways to improve, and optimise this function, and I'm certain there are different ways of solving it. 

But I believe in taking the simplest, most pragmatic approach, and the tradeoffs I believe are worth it.

#### Resources:

Repository: https://github.com/Seroxdesign/Sequencer-Monitor/
Discord Server: https://discord.gg/wx2tDkf8Ct
