This is the AVADO package of MEV-Boost, the open-source middleware that lets a validator take block bids from many builders through relays.
It runs mev-boost on mainnet with a list of relays that this repository keeps current, so stakers get more bids without editing a long relay string by hand.
relays.json is the single source of truth for the mainnet relays. Everything else is generated from it: relays.md (the table and the copy-paste relay string), the RELAYS default in the package, the list of shut-down hosts in build/start.sh, and the live list that the AVADO Admin shows.
Top-level fields:
| Field | Meaning |
|---|---|
schema |
Always 1. |
updatedAt |
The date (YYYY-MM-DD) the list last changed. The Admin uses it to tell whether its own copy is older. |
network |
Always mainnet. |
relays |
One entry per relay, in the order they are shown. |
Each relay:
| Field | Meaning |
|---|---|
id |
A short lower-case name, unique in the file (for example ultrasound). |
name |
The name people see (for example Ultra Sound). |
url |
The relay URL as mev-boost takes it: https://0x<public key>@<host>. Hosts are unique. |
about |
An https link where people can read about the relay. |
filtering |
none, or sanctions when the relay leaves out transactions from sanctioned addresses. |
recommended |
true when "Use recommended" in the Admin should tick it. Only a live relay can be recommended. |
status |
live, or retired when the relay no longer answers. |
statusSince |
The date the status last changed. |
note |
A short sentence for people, or an empty string. |
For the relays seeded on 2026-10-11, statusSince is the date the list was created, not the date the relay actually stopped.
scripts/relays.schema.json describes the same rules for editors; node scripts/check-relays.mjs checks them.
Every Monday at 06:00 UTC the Relay check workflow (.github/workflows/relay-check.yml) runs node scripts/probe.mjs. It:
- Asks every relay in the list, plus any relay that is new on the ethstaker relay list, whether it is up (
/eth/v1/builder/status, three tries each). - Counts how many weekly checks in a row each live relay has failed, in
.relay-check/failures.json. A relay is retired only after three failed weekly checks in a row; one or two misses are just warnings. A success resets the count. A retired relay keeps its count until it answers again, so a retirement that is not merged yet is made again the next week instead of being lost. - Brings a retired relay back as live when it answers again, but leaves it not recommended.
- Adds a relay that is new on the ethstaker list as not recommended, and warns (without changing anything) when the ethstaker list shows a different public key for a relay we already have. A row on the ethstaker list that is not a valid relay URL (for example
http://, or a path after the host) is left out with a warning, and the rest of the check goes on. - Checks the new list the same way the tests do, then opens or updates a pull request called Relay check with
relays.json,relays.mdand.relay-check/failures.json. The pull request text lists every relay, the changes and the warnings. A pull request opens whenever one of those three files changed, including when only a failure count went up. When none of them changed, no pull request is opened.
Some weeks the pull request only carries warnings (a relay missed one or two checks). Merging those is optional. Each run starts from the counts on the open relay-check branch, so missed checks keep adding up whether or not the warning-only pull request was merged.
The weekly pull request needs the repository setting Allow GitHub Actions to create and approve pull requests (Settings → Actions → General → Workflow permissions). A pull request opened by a workflow does not start the test workflow, so the check validates the list in the same run before it opens the pull request.
Nothing reaches the boxes until the owner reviews and merges that pull request. Whether a relay should be recommended is always the owner's decision: merge the weekly pull request first, then change recommended in a separate pull request (edit relays.json, run npm run render, open a pull request). Edits pushed to the relay-check branch are overwritten by the next Monday run.
To see what the check would do without changing any file: node scripts/probe.mjs --dry-run.
When a change to relays.json lands on main, the Publish relay list workflow (.github/workflows/publish-relays.yml) checks the file and runs node scripts/publish.mjs. That writes the whole file to bo.ava.do as the value mev-relays and reads it back from https://bo.ava.do/value/mev-relays to make sure the new updatedAt is there. The repository always wins: every publish overwrites what bo.ava.do had.
The Relays card on the MEV-Boost page of the AVADO Admin reads that value, so boxes see the new list the next time the card is opened, without a package release. When bo.ava.do cannot be reached, the card falls back to the copy bundled with the Admin.
The publish workflow can also be started by hand from the Actions tab (Run workflow). It only publishes when started on main, so an unmerged list can never reach the boxes.
Publishing needs a bo.ava.do admin token in the repository secret BO_ADMIN_TOKEN (Settings → Secrets and variables → Actions). Without it the publish job fails with "BO_ADMIN_TOKEN is not set" and the boxes keep the previous list.
- Edit
relays.json. SetupdatedAtto today's date, andstatusSincetoo when you change a relay's status. - Run
npm run renderto regeneraterelays.md. - Run
npm testandnpm run check. - Open a pull request. Tests run on it; the package build is skipped because only the list changed. Merging publishes the list as described above.
The relay defaults inside the package are only updated when a new version is released:
- Branch from an up-to-date
main. - Run
node scripts/render.mjs package. It rewrites theRELAYSdefault indappnode_package.jsonanddocker-compose.ymlandDEAD_RELAY_HOSTSinbuild/start.shfromrelays.json. - Bump the version in
dappnode_package.jsonand the image tag indocker-compose.yml. - Run
npm run test:start. It runsbuild/start.shwith plainshagainst a stand-in for mev-boost and checks that retired relays are skipped, that "Relays in use" is printed, and that no minimum bid is passed unlessEXTRA_OPTSsets one. - Open a pull request. The build workflow builds the package; when it is merged (with a merge commit, never a squash, because the release job applies the build's diff) the release workflow publishes the new version. The owner moves it to production.
A relay that comes back after being retired stays skipped by the running package's built-in list of retired hosts (DEAD_RELAY_HOSTS in build/start.sh) until the next package release.
When the RELAYS default in dappnode_package.json no longer matches relays.json, the test workflow prints a warning line in its log (not in the job summary, and the job still passes); that is the reminder to prepare a release.
Since 0.0.19 the package sets no minimum bid (EXTRA_OPTS= is empty), so the validator takes the best bid a relay offers. Before 0.0.19 it shipped -min-bid 0.05, and since most bids are now lower than that, many blocks fell back to a block the box built itself. Existing installs keep the value they have until it is changed in the Admin.
Node 20 or newer, no dependencies.
npm test # unit tests (node --test)
npm run test:start # test build/start.sh with sh and a stand-in for mev-boost
npm run check # validate relays.json and check relays.md is up to date
npm run render # regenerate relays.md
node scripts/render.mjs package # write the relay defaults into the package files
node scripts/probe.mjs --dry-run # run the weekly check without writing anything