Skip to content

Relayers

Hyperbridge relayers
Hyperbridge relayers

Critical to the function of Hyperbridge are the relayers who transmit requests & responses across it's connected chains. Unlike popular interoperability protocols, Hyperbridge relayers are fully permissionless. This means, relayers will not need to be staked or whitelisted in order to transmit cross-chain messages. This is as a result of it's first-of-it's kind, fully trust-free design. This service of-course, will not be for free. Hyperbridge permits the applications that leverage it’s secure message passing infrastructure to pay ahead of time for the message delivery & execution. They do so on the source chain of the initiating application.


Fees for cross-chain requests are to be paid in stable coins, We’ve chosen the DAI stablecoin for it’s decentralized and censorship-resistant properties. This means users will estimate the cost for message execution & provide what they believe to be a fair amount in DAI to the Hyperbridge contract. (Specifically, the EvmHost) at the time of dispatching a request. Once the request has been finalized by the originating chain and these finality proofs made available to the destination chain. The request becomes eligible for delivery & execution. A relayer will estimate the cost of request delivery and query the fee that has been put up for it’s delivery on the source chain. Depending on their profitability configuration, they’ll either choose to deliver the request or ignore it.


If the relayers chooses to deliver the request, then this means they will cover the cost of message delivery and execution. This cost of message delivery is the cost of proof verification of requests & responses. The cost of message execution is the cost of executing the message on the destination module. In the current version of the protocol, relayers are tasked with both delivering and executing the messages. But it is entirely possible in future versions of the protocol that we unbundle message delivery and execution as this may enable more exotic applications.


In our chosen design, relayers race to deliver a batch of cross-chain messages to their respective destination chains. This has a few benefits, this effectively mitigates any liveness issues that may arise as a result of some whitelisted relayers going down. This free market design presents a much better UX to end users and applications. The winning relayer, can be decided by a few factors.


  1. Block notification.

Relayer are mostly idle, and will only check for new messages to be delivered when the chains they’re interested in receive new consensus messages. The consensus messages, contain proofs that finalizes a new set of block heights. The new block heights, may or may not contain new messages to be delivered from the hyperbridge parachain. Therefore, whichever relayer sees the block where these consensus messages were processed on the destination chain first, can begin the check before everyone else and as a result, deliver the new batch of requests before anyone else.

  1. Query throughput

We can for the purposes of this criteria assume that every single relayer has received the block notification at the same time. Now they have to do a few things, first they’ll query for the new requests available, next they’ll need to query the fees associated with these requests, and finally query the cost of executing these requests by simulating them individually as a transaction on the full node for it’s destination chain.

If the relayer is able to query high-performance nodes and has a very fast internet connection, or even better is colocated the nodes in question. You can already see how this provides an edge in being the first to deliver the requests.

  1. MEV

An unfortunate development in blockchain protocols are validators who auction their blockspace. They do so in order to earn even more money than the underlying protocols already pay them. It’s not impossible that relayers may integrate with validators who auction their blockspace using proposer-builder networks in order to have their bundles always be first in the block. Of-course these relayers would have to pay high priority fees for such shenanigans. But we fully expect relayer competition to eventually reach these levels.


Once a relayer successfully delivers a batch of requests, they can immediately start claiming the associated fees for these requests. They’ll do so by submitting state proofs of the messages delivered on the destination chain to hyperbridge. Once hyperbridge verifies these proofs, it will make the fees available to the relayer by issuing a request to it’s contracts on the source chain. The relayer will be responsible for delivering this request as it will have no fee attached and will hence be ignored by other relayers.

Installation

The tesseract relayer is available through the following methods

Prebuilt binaries

Unavailable at this time.

Docker

Tesseract is available at the official docker repository polytopelabs/tesseract

docker run polytopelabs/tesseract:latest --config=/path/to/config --db=/path/to/database

Building from source?

Unfortunately, tesseract is closed-souce for now. Tesseract source-code will be available on Hyperbridge mainnet launch.

Running the relayer

The tesseract relayer command line interface expects two arguments, which are the paths to it's configuration file and database file. Because it resides in a docker container, you will need to map the directory where you've stored the configuration files on your host into the docker conatiner. Tesseract will write it's database to that directory once it's initialized.

docker run -d \
  --name=tesseract \
  --network=host \
  --restart=always \
  --volume=/dir/on/host:/home/root \
  polytopelabs/tesseract:latest \
  --config=/home/root/config.toml \
  --db=/home/root/dev.db

Access it's logs using

docker logs -f tesseract

System Requirements

At the minimum, the hyperbridge relayer should be run on a machine with at least 4GB of RAM and a quad-core cpu. This relayer should also have at least a 100Mb/s connection if it is to query nodes over the internet.

Ansible Playbooks

A community member has graciously provided their ansible playbook for running the hyperbridge relayer. You can find it here:

https://github.com/schmiatz/hyperbridge-relayer

Configuration

The configuration file is a toml file that at the moment, that expects the following configuration options:

# Hyperbridge config, required
[hyperbridge]
# Hyperbridge chain spec, either one of Dev, Gargantua, Gargantua-Rococo, Messier or Nexus
chain = "Gargantua" # testnet
# Hyperbridge node ws rpc endpoint.
rpc_ws = "ws://127.0.0.1:9944" # example endpoint
# Sets the maximum size of an rpc request or response in bytes defaults to 150mb
max_rpc_payload_size = 150000000
 
[ethereum]
# configuration type
type = "ethereum_sepolia"
# State machine identifier
state_machine = { Ethereum = "ExecutionLayer" }
# http(s) rpc url for sepolia
rpc_url = ""
# consensus state identifier for sepolia on hyperbridge
consensus_state_id = "ETH0"
# etherscan api key for querying Ethereum token price
etherscan_api_key = ""
# Contract address of the HandlerV1 contract
handler = ""
# Contract address of the IsmpHost contract
ismp_host = ""
# Maximum block range for eth_getLogs in a single rpc call
# if this parameter is not supplied the range will not be split into smaller chunks
query_batch_size = 1000
# hex-encoded private key for the relayer
signer = ""
 
[arbitrum]
# configuration type
type = "arbitrum"
# State machine identifier
state_machine = { Ethereum = "Arbitrum" }
# http(s) rpc url for arbitrum
rpc_url = ""
# consensus state identifier for arbitrum on hyperbridge, L2s use ethereum as their consensus oracle
consensus_state_id = "ETH0"
# etherscan api key for querying Ethereum token price
etherscan_api_key = ""
# Contract address of the HandlerV1 contract
handler = ""
# Contract address of the IsmpHost contract
ismp_host = ""
# Maximum block range for eth_getLogs in a single rpc call
# if this parameter is not supplied the range will not be split into smaller chunks
query_batch_size = 1000
# hex-encoded private key for the relayer
signer = ""
 
[optimism]
# configuration type
type = "optimism"
# State machine identifier
state_machine = { Ethereum = "Optimism" }
# http(s) rpc url for optimism
rpc_url = ""
# consensus state identifier for optimism on hyperbridge, L2s use ethereum as their consensus oracle
consensus_state_id = "ETH0"
# etherscan api key for querying Ethereum token price
etherscan_api_key = ""
# Contract address of the HandlerV1 contract
handler = ""
# Contract address of the IsmpHost contract
ismp_host = ""
# Maximum block range for eth_getLogs in a single rpc call
# if this parameter is not supplied the range will not be split into smaller chunks
query_batch_size = 1000
# hex-encoded private key for the relayer
signer = ""
 
[base]
# configuration type
type = "base"
# State machine identifier
state_machine = { Ethereum = "Base" }
# http(s) rpc url for base
rpc_url = ""
# consensus state identifier for base on hyperbridge, L2s use ethereum as their consensus oracle
consensus_state_id = "ETH0"
# etherscan api key for querying Ethereum token price
etherscan_api_key = ""
# Contract address of the HandlerV1 contract
handler = ""
# Contract address of the IsmpHost contract
ismp_host = ""
# Maximum block range for eth_getLogs in a single rpc call
# if this parameter is not supplied the range will not be split into smaller chunks
query_batch_size = 1000
# hex-encoded private key for the relayer
signer = ""
 
[bsc]
# configuration type
type = "bsc"
# State machine identifier
state_machine = "Bsc"
# http(s) rpc url for binance smart chain
rpc_url = ""
# consensus state identifier for binance smart chain on hyperbridge
consensus_state_id = "BSC0"
# etherscan api key for querying BNB token price
etherscan_api_key = ""
# Contract address of the HandlerV1 contract
handler = ""
# Contract address of the IsmpHost contract
ismp_host = ""
# Maximum block range for eth_getLogs in a single rpc call
# if this parameter is not supplied the range will not be split into smaller chunks
query_batch_size = 1000
# hex-encoded private key for the relayer
signer = ""
 
 
# Relayer config, required
[relayer]
# Define your profitability configuration. 0 -> 0% i.e relay all requests, even unprofitable ones. 1 -> 1%. ie fees provided for requests must be profitable by at least 1%. etc.
minimum_profit_percentage = 0
# (Optional) If not empty, will filter requests to be delivered by originating module identifier (eg contract address)
module_filter = []
# How frequently to initiate withdrawals in seconds, defaults to 24 hours
withdrawal_frequency = 86400
# Minimum amount to withdraw when auto-withdrawing, defaults to $100
minimum_withdrawal_amount = 100
# (Optional) If not empty, only deliver to the specied state-machines
delivery_endpoints = [
    { Ethereum = "ExecutionLayer" },
    { Ethereum = "Arbitrum" },
    { Ethereum = "Optimism" },
    { Ethereum = "Base" },
    "Bsc"
]

It is optional to provide the configuration option for any of the connected chains, The only consequence is your relayer will not deliver requests from the ommitted chain as it has no way of querying the associated fees for requests originating from this chain.

You can obtain the required etherscan API key by following this guide for the appropriate network. Do note that since Ethereum and it's L2s all use Ether as the gas token. They can all share the same etherscan API key.

Contract addresses

You can find the up-to-date contract addresses for the Handler & IsmpHost contracts here

Withdrawing Fees

Tesseract maintains a local sqlite database where it keeps track of successfully delivered messages. The withdrawal process happens in two phases, the first phase is the fee accumulation on hyperbridge, then withdrawal on any of the connected chains. In the fee accumulation phase, tesseract submits state proofs of messages all delivered to hyperbridge. If the proof verification is successful, the total amount of unclaimed fees for the relayer address is updated onchain. Next, the relayer can submit a withdrawal transaction to hyperbridge. This initiates potentially multiple ISMP requests to any chain where it has unclaimed fees, that instructs the Hyperbridge contract to credit the relayer their owed funds. This request will not timeout, allowing it to be submitted to the destination chain at any time.

Accumulating fees

Stop any running relayer instances, run the following command in the terminal and wait for it to complete. The command will submit proofs for messages delivered to all chains present in the config file.

    docker run --network=host -v /dir/on/host:/home/root polytopelabs/tesseract:latest --config=/home/root/config.toml --db=/home/root/dev.db accumulate-fees

When accumulating fees the required state machine update to verify the proofs might not yet be available on hyperbridge, by default accumulating fees for those state machines will be skipped. To wait for all state machine updates.

    docker run --network=host -v /dir/on/host:/home/root polytopelabs/tesseract:latest --config=/home/root/config.toml --db=/home/root/dev.db accumulate-fees --wait

Initiating withdrawals

To initiate a withdrawal from hyperbridge, a relayer needs to submit a transaction to hyperbridge with triggers the withdrawal request. This extrinsic is unsigned and will not require any native tokens for execution fees.Once the extrinsic is executed, hyperbridge dispatches a POST request that when executed on it's destination, will provide the relayer with the fees they've accrued. The relayer account must have sufficient funds to deliver this request to it's destination chain.


To use this feature run the following command:

    docker run --network=host -v /dir/on/host:/home/root polytopelabs/tesseract:latest --config=/home/root/config.toml --db=/home/root/dev.db accumulate-fees --withdraw

Automatic accumulation and withdrawals

The relayer also runs background tasks for automatic fee accumulation and withdrawals. Whenever a batch of messages is successfully delivered, the fee accumulation task receives the delivery receipts and starts the process of accumulating the fees on hyperbridge. This process happens concurrently for all successfully delivered message batches. For redundancy, the delivery receipts are stored in the database prior to accumulation so they can be retried manually if any error is encountered.


Withdrawing fees from hyperbridge is triggered at fixed intervals based on the configured withdrawal_frequency and minimum_withdrawal_amount. Feel free to the adjust these values as desired. The task will only make a withdrawal attempt if your balance on hyperbridge is greater than or equal to the configured minimum_withdrawal_amount. Any failed withdrawal attempts will be retried each time the withdrawal task is triggered. The manual processes described in the previous sections can be used as fallbacks when errors are encountered by their automated conterparts.