# Relayer The wormhole relayer is designed to answer one main question: Q: How do you transfer to a new wallet in a destination chain when you lack native tokens for paying gas fees? A: You pay a little bit more on the source chain and use that to pay gas fees on the destination chain. It was originally designed for payload version 1 token transfers, but should be extensible to other payload types as well. ## Architecture | Component | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | Guardian Spy | Connects to the wormhole p2p network and publishes all VAAs to a websocket | | Spy Listener | Filters VAAs from the Spy and adds them to the incoming queue in Redis | | REST Listener | Accepts HTTP requests to relay VAAs and writes them to the incoming queue in Redis | | Redis | A durable queue for storing VAAs before they are relayed | | Relayer | Scans the Redis incoming queue and moves acceptable VAAs to the working queue. It then completes the transfer and pays gas fees on the destination chain. | | Wallet Monitor | Presents a prometheus endpoint for monitoring wallet balances of native tokens (for paying gas fees) and non-native tokens as relayer profit | If Redis is temporarily down, the Listener will queue outstanding transactions in memory. When Redis comes back online, the Listener writes them all to Redis. ### Architecture Diagram This is a rough diagram of how the components fit together: ┌────────────────────────────────────────┐ │ Wormhole Guardian Peer to Peer Network │ └───────────────────┬────────────────────┘ │ ┌──────▼───────┐ │ Guardian Spy │ └──────┬───────┘ │ ┌──────▼───────┐ │ Spy Listener │ └──────┬───────┘ │ ┌───▼───┐ ┌───────────────┐ │ Redis │◄───┤ REST Listener │ └───┬───┘ └───────────────┘ │ ┌────▼────┐ │ Relayer │ └─────────┘ │ ┌────────▼───────┐ │ Wallet Monitor │ └────────────────┘ ## Environment Variables ### Listener These are for configuring the spy and rest listener. See [.env.tilt.listener](.env.tilt.listener) for examples: | Name | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `SPY_SERVICE_HOST` | host & port string to connect to the spy | | `SPY_SERVICE_FILTERS` | Addresses to monitor (Wormhole core bridge contract addresses) array of ["chainId","emitterAddress"]. Emitter addresses are native strings. | | `REDIS_HOST` | Redis host / ip to connect to | | `REDIS_PORT` | Redis port | | `REST_PORT` | Rest listener port to listen on. | | `READINESS_PORT` | Kubernetes readiness probe port to listen on. | | `LOG_LEVEL` | log level, such as debug | | `SUPPORTED_TOKENS` | Origin assets that will attempt to be relayed. Array of ["chainId","address"], address should be a native string. | ### Relayer These are for configuring the actual relayer. See [.env.tilt.relayer](.env.tilt.relayer) for examples: | Name | Description | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `SUPPORTED_CHAINS` | The configuration for each chain which will be relayed. See [chainConfigs.example.json](src/chainConfigs.example.json) for the format. Of note, `walletPrivateKey` is an array, and a separate worker will be spun up for every private key provided. | | `REDIS_HOST` | host of the redis service, should be the same as in the spy_listener | | `REDIS_PORT` | port for redis to connect to | | `PROM_PORT` | port where prometheus monitoring will listen | | `READINESS_PORT` | port for kubernetes readiness probe | | `CLEAR_REDIS_ON_INIT` | boolean, if `true` the relayer will clear the INCOMING and WORKING Redis tables before it starts up. | | `DEMOTE_WORKING_ON_INIT` | boolean, if `true` the relayer will move everything from the WORKING Redis table to the INCOMING one. | | `LOG_LEVEL` | log level, debug or info | ## Building ### Building the Spy To build the guardiand / spy container from source: ```bash cd node docker build -f Dockerfile -t guardian . ``` ### Building the Relayer application Build the relayer for non-containerized testing: ```bash cd relayer/spy_relayer npm ci npm run build ``` ## Running the Whole Stack For Testing This config is mostly for development. ### Run Redis Start a redis container: ```bash docker run --rm -p6379:6379 --name redis-docker -d redis ``` ### Run the Guardian Spy The spy connects to the wormhole guardian peer to peer network and listens for new VAAs. It publishes those via a socket and websocket that the listener subscribes to. If you want to run the spy built from source, change `ghcr.io/wormhole-foundation/guardiand:latest` to `guardian` after building the `guardian` image. Start the spy against the testnet wormhole guardian: ```bash docker run \ --platform=linux/amd64 \ -p 7073:7073 \ --entrypoint /guardiand \ ghcr.io/wormhole-foundation/guardiand:latest \ spy --nodeKey /node.key --spyRPC "[::]:7073" --network /wormhole/testnet/2/1 --bootstrap /dns4/wormhole-testnet-v2-bootstrap.certus.one/udp/8999/quic/p2p/12D3KooWAkB9ynDur1Jtoa97LBUp8RXdhzS5uHgAfdTquJbrbN7i ``` To run the spy against mainnet: ```bash docker run \ --platform=linux/amd64 \ -p 7073:7073 \ --entrypoint /guardiand \ ghcr.io/wormhole-foundation/guardiand:latest \ spy --nodeKey /node.key --spyRPC "[::]:7073" --network /wormhole/mainnet/2 --bootstrap /dns4/wormhole-mainnet-v2-bootstrap.certus.one/udp/8999/quic/p2p/12D3KooWQp644DK27fd3d4Km3jr7gHiuJJ5ZGmy8hH4py7fP4FP7 ``` ### Run The Apps This runs the Spy Listener, REST Listener, Relayer, and Wallet Monitor all in a single process for development and testing purposes: Start the application: ```bash npm ci npm run spy_relay ```