# Introduction

### What is the Bifrost Network?

The Bifrost Network is a public blockchain built on the Substrate framework and fully compatible with the Ethereum API, providing developers with access to a wide range of libraries and development environments.

The Bifrost Network is designed with a "multichain-first" approach, which natively enables interaction and communication between different blockchains through a decentralized cross-chain channel. DApps on the Bifrost Network can utilize a range of promising cryptocurrencies from any supported blockchains through the Bifrost Network's cross-chain communication protocol. The core validators on the Bifrost Network also serve as relayers, transmitting cross-chain messages across multiple blockchains to facilitate this communication. This cross-chain readiness creates a multichain-oriented environment that offers developers huge opportunities to develop innovative and diverse applications.

### What makes developing and running applications on the Bifrost Network  enjoyable?

#### Cross-chain Interoperability

The Bifrost Network has its own Cross-Chain Communication Protocol (CCCP) that enables native support for cross-chain actions. Overcoming the inherent limitations of multichain (i.e., fragmented liquidity and market), DApps can offer their services to a broader range of users and provide more comprehensive services.

**Built-in token bridge interacting with DApps:** CCCP is a key component of the Bifrost Network that enables the seamless transfer of tokens between different blockchain networks. Designated contracts on the Bifrost Network manage the cross-chain transfer of tokens at the smart contract level. By using CCCP, decentralized applications (DApps) can easily integrate cross-chain token transfer actions into their services.

**Multichain-ready resources (Token and Oracle):** One of the main challenges faced by DApps operating across multiple blockchain networks is accessing and using primary resources, such as tokens and oracle data feeds, from different blockchain networks due to their inherent incompatibilities. This lack of clarity on handling multichain assets can hinder the development and adoption of DApps. The Bifrost Network supports representative forms of primary resource that is optimized for use with CCCP.

**Extending legacy single-chain DApps to support multichain:** CCCP provides bridge integration methods (e.g., *Bridge* and *BridgeAndCall*) at smart contract level so that DApps can extend their actions for a single blockchain to interwork with DApps in the Bifrost Network. It allows developers to convert their regular DApps into multichain DApps by integrating them with the Bifrost Network.

#### DApp-Friendly Environment

The Bifrost Network is a well-established and fully-equipped platform for DApps developers, built on the extensive experience of a long-time service provider of BiFi. It offers essential features and resources to support the development and operation of DApps.

**Price oracle aggregation:** The Bifrost Oracle is a reliable source for cryptocurrency prices, offering real-time data for decentralized finance (DeFi) services. By aggregating and verifying data from both on-chain and off-chain data sources, the Bifrost Oracle helps to prevent unexpected price spikes and manipulation attacks. In addition, the low gas fee of the Bifrost Network allows the Bifrost Oracle to update its price data more frequently than other oracle services, providing users with accurate, up-to-date information that closely reflects real-time market prices.

#### EVM Compatibility

The Bifrost Network supports smart contracts on the Ethereum Virtual Machine (EVM). Developers may create DApp in Solidity and use the following well-known tools and resources to aid in the development process.&#x20;

* **Seamless migration of essential Solidity library.** e.g., OpenZeppelin’s SafeMath, SafeERC20, SafeProxy.
* **Compatibility with client libraries.** e.g., Web3, Ether.js, Web3.py.
* **Development environments.** e.g., HardHat, Brownie, Truffle, Metamask.
* **Security analysis tools.** e.g., Manticore, Mythril, Oyente, Solgraph.
* **Ethereum asset standards.** e.g., ERC-20, ERC-721.

####


# Bifrost Network Architecture

The Bifrost Network is an EVM-compatible blockchain designed for multichain interoperability, allowing users and the DApp developers in the Bifrost Network ecosystem to interact with multiple blockchains through native cross-chain communication. The Bifrost Network initially supports timelock-secured token transfers and oracle aggregations across blockchains.

A fully-functioning node in the Bifrost Network is composed of the base part and the inter-connection part, or "relayer." The base part, built with Substrate and the Bifrost precompiles, is responsible for producing and finalizing blocks. At the same time, the relayer monitors multiple blockchains and securely executes cross-chain actions through in-blockchain consensus.

### Cross-Chain Communication

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FZqZF3dUmx3aLacfFztxo%2FBIFROST%20IR%20Report_03_EN%20(3).png?alt=media&amp;token=1f61eaf3-6ac9-4345-9369-3f5f81b4be48" alt=""><figcaption></figcaption></figure>

Cross-Chain Communication (CCC) is a protocol that facilitates the delivery and verification of cross-chain actions in the Bifrost Network. It uses specialized smart contracts called "socket contracts" to coordinate relayers and cross-chain users on every supported blockchain.&#x20;

A user sends a request to the socket contracts to initiate a cross-chain action. If the socket contract can successfully validate the request, the relayers are notified and deliver the request to a socket contract on the other blockchain. CCC uses in-blockchain consensus to verify the request, including the current state of the cross-chain action and the signature of the relayer. The socket contract can only execute the cross-chain action when a quorum of authenticated relayers agree on the request and it is in a legitimate state.


# Consensus

### Delegated **Proof of Stake**

Bifrost is based on a **Delegated Proof of Stake (DPoS)** system where nominators back validators with their own staked BFC as a show of faith in the good behavior of the validator. Anyone who has BFC staked in the DPoS-based Bifrost Network can participate in the network consensus process as a validator or a nominator (the exact amounts are TBD).&#x20;

The Bifrost Network updates the current active validator set every round. A new active validator set is selected based on which validators have the highest voting power – the total voting power of an individual validator consists of the sum of their self-bonded stake and received nominations. Only the top *n* will be selected as the active validators authorized to participate in the consensus for the new round. At the end of each round, validators earn round rewards in return for maintaining the security and reliability of the Bifrost Network. Some of the validator’s round rewards will be proportionally distributed to each of their nominators.&#x20;

Validators that do not behave properly may be designated as a target for slashing and receive a penalty that deducts a percentage of their staked BFC. Validators are incentivized to maintain a high level of voting power within the network in order to remain in the active validator set and continue to earn rewards; or so that they can increase their chances of being selected as an active validator. Nominators are incentivized to vote for reliable validators to ensure that their stakes are maintained and rewarded. Over time, the voting power of each validator will be equivalent to the confidence that the total body of nominators has in that validator to support and secure the network. This set of consensus mechanisms and rewards is based on mutual trust and symbiotic relationships that improve both the stability and reliability of the network.

### **Block Production**

Bifrost's block production engine is **AuRA** (Authority Ro(a)und). AuRa works by sequentially selecting the block producer for the current slot in a round-robin fashion. If the network is stable, all active validators will create the exact same number of blocks for each round.

### Finality Gadget

Bifrost's block finalization engine is **GRANDPA** (GHOST-based Recursive Ancestor Deriving Prefix Agreement). GRANDPA is a consensus approach based on deterministic finality. All active validators selected in each round must participate in the voting process to determine the finality of the block.

The voting process begins by selecting a **primary node**. The primary node then selects the highest block in the chain from that node's point of view and broadcasts its block data to the network. After when the rest of the nodes receive the block data, they vote on the block to achieve finality. If the block is affirmed by more than two-thirds of all active validators, all blocks below that block number will be finalized.


# Cross-Chain Communication Protocol (CCCP)

## Introduction

Bifrost's Cross-Chain Communication Protocol (CCCP) realizes cross-chain communication through interactions between socket contracts and relayers. The CCCP enables users on one blockchain to utilize DApps provided on other blockchains.

A socket contract is a system contract installed on the Bifrost Network and all other external chains such as Ethereum. A socket contract emits a CCC-event when triggered by a CCC-request from another socket contract, and this CCC-event is delivered to another socket contract by a relayer. A user’s request goes around different socket contracts in the form of a CCC-event and terminates when all the necessary logic has been executed.

In particular, multiple relayers deliver the socket-events to ensure the protocol’s continuity even if a certain number of relayers fail or are compromised, and the “timeout rollback” function is in place to prevent the users’ assets from being locked in socket contracts even if the entire relayer group fails. Additionally, the total operational cost of the relayer group is significantly cut down by minimizing the number of transactions delivered to other blockchains that have relatively high costs.

## Glossary

* **CCC Protocol (CCCP)**: Cross-Chain Communication Protocol&#x20;
* **VS Protocol (VSP)**: Validator Synchronization Protocol&#x20;
* **Validator**: the consensus validation node of the Bifrost Network&#x20;
* **Relayer**: the CCC protocol-worker node of the Bifrost Network
* **CCC-request**: is requested by a user which calls an *f(x)* installed on other blockchains&#x20;
* **CCC-event**: a CCCP message containing the CCC-request details (socket contract’s event)&#x20;
* **External chain**: any blockchain other than the Bifrost Network (e.g. Ethereum, BNB chain, Polygon, etc.)
* ***f(x)***: a pre-defined function to be executed in other blockchains. (smart contract)&#x20;
* **Positive status**: the CCC-status indicating “success” (REQUESTED, EXECUTED, ACCEPTED, COMMITTED)&#x20;
* **Negative status**: the CCC-status indicating “failure”; the positive and negative statuses have been accordingly paired (FAILED, REVERTED, REJECTED, ROLLBACKED)

## Components

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FFe4WfImGYbp9cUE1ZCGO%2FBifrost%20Network%20Components.png?alt=media&amp;token=df58c08e-c026-41bc-a03b-f4be522fc56e" alt=""><figcaption></figcaption></figure>

A **user** sends a CCC-request to the socket contract, which calls a *f(x)* under another blockchain. As a *f(x)* requires cryptocurrency payment, the socket contract collects the user’s cryptocurrency.

**Relayers** deliver the following data to the socket contract:

* **Latest validator (relayer) list**: relayers deliver the latest validator list to all external chains; all blockchains utilize the latest validator list for access control
* **Off-chain data:** off-chain data such as certain assets’ prices or Bitcoin blockchain’s block hash are delivered to the Socket contract of the Bifrost Network; the oracle manager contract receives this data from the socket contract and provides oracle services
* **CCC-events**: a relayer detects CCC-events from all supported blockchain networks and relays the detected event to its corresponding socket contract; the corresponding socket contract information can be derived from the CCC-event

**System Contracts -** The Bifrost Network supports the three system contracts:

* **The socket contract** generates CCC-events which are to be treated by other socket contracts, or receives CCC-events emitted by other socket contracts and treats them. In particular, it executes request-indicated actions (e.g. mint, lending, leveraged investment) according to the protocol specifications.
* **The Built-in DeFi Suite** - The DeFi Suite functions are abstracted and expressed as *f(x)*.
* **The oracle manager contract** collects the designated off-chain data and provides on-chain oracle services.

## Protocol Design

The following design factors are applied to the CCCP to overcome the limitations of the smart contracts' execution environment.

**Design Factors**

* As smart contracts do not provide sufficient data storage space, we only store the data’s hash instead of the entire data in smart contracts. If we need to reuse the data, we re-send it. We use this strategy because comparing the hash value is cheaper than initially storing the data.&#x20;
* A transaction may fail due to its atomic property. In this case, another transaction indicating this “failure” must be re-transmitted to leave its failed status on the smart contract.
* Smart contracts do not provide built-in functions such as sorting array or mapping keys/values return, and implementing such functions is inefficient transaction fee-wise. Thus, the transaction sender may have to send an already sorted array data so that the smart contract does not have to do the sorting.
* We minimize the number of transactions directed to external chains which impose relatively high fees. When a relayer group relays a CCC-event to an external chain, the CCC-event is first submitted with a signature to the Bifrost Network. Then, the primary relayer aggregates all signatures and delivers them to the external chain at once.

VSP is the sub-protocol of CCCP, which synchronizes the latest validator list of the Bifrost Network to all external chains. The validator list must stay up to date as the validators of the network can change periodically and socket contracts use information about validators for access control.

### Assumptions

* *Relayers* monitor every *CCC-event.*&#x20;
* *Relayers* possess sufficient amounts of native coins (e.g. BFC, ETH, BNB) for transaction fees.&#x20;
* *Relayers* are penalized for request forgeries. (*Relayers* do not harm the protocol for minor gains.)&#x20;
* The majority of *relayers* faithfully execute the protocol. (The number of *relayers* in shut down status or conducting request forgery attacks is always less than the majority.)&#x20;
* The preceding *CCC-event* accumulation will not cause the failure of the following *CCC-event* production.
* *Relayers* process all events generated during their delegated time, even if they are un-delegated for any reason.&#x20;
  * *Relayers* process all requests that occur during their term.&#x20;
  * The Bifrost Network relays the next validator set.&#x20;
  * Otherwise, *relayers* are penalized.

### Inbound CCCP

The inbound protocol indicates the delivery method of the CCC-request from an external chain to the Bifrost Network. The figure below represents the CCC-event flow of the inbound protocol. The “relay type” marked for each relay is further explained in the section "Two-Types of Relay Vote".

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F2bDtuQANimxgKh6SpyIz%2FInbound%20CCCP.png?alt=media&amp;token=3cd522a1-4863-492e-931d-6850dc7403c7" alt=""><figcaption></figcaption></figure>

Each user request delivered to the socket contract of an external chain sequentially goes through **“REQUESTED”**, **“EXECUTED”,** and **“ACCEPTED”** and finally ends in “**COMMITTED**” status. However, if the Phase 1 *f(x)* fails to execute, a request goes through “**REQUESTED**”, “**REVERTED**”, and “**REJECTED**” and ends in “**ROLLBACKED**” status. Requests completed as “**ROLLBACKED**” return the collected tokens during the user’s transaction.

### Outbound CCCP

The outbound protocol indicates the delivery method of the user request from the Bifrost Network to an external chain. The figure below represents the CCC-event flow of the outbound protocol. The “relay type” marked for each relay is further explained in the section "Two-Types of Relay Vote".

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FOuULwTRnC1H2bgfqWZam%2FOutbound%20CCCP.png?alt=media&amp;token=4ed82289-5eac-438f-9dfc-69da2651ea54" alt=""><figcaption></figcaption></figure>

Each user request delivered to the socket contract of an external chain sequentially goes through “**REQUESTED**”, “**EXECUTED**”, “**ACCEPTED**” and finally ends in “**COMMITTED**” status. However, if the Phase2 *f(x)* fails to execute, a request goes through “**REQUESTED**”, “**REVERTED**”, “**REJECTED**” and ends in “**ROLLBACKED**” status. Requests completed as “**ROLLBACKED**” return the collected tokens during the user’s transaction.'

### **Validator Synchronization Protocol**

VSP delivers the updated information on the Bifrost Network’s validator(=relayer) set to all socket contracts on all supported external chains. Socket contracts update their access permission list with the delivered validator set.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2Fv2zrtj8Snov8Yc9lAWxq%2FValidator%20Synchronization%20Protocol.png?alt=media&amp;token=dfcf1ee2-7d6c-4b68-952e-888b360b03ff" alt=""><figcaption><p>This protocol functions in a way similar to that of Phase 1 and Phase 2 of the outbound protocol.</p></figcaption></figure>

## **Two Types of Relay Vote**

A CCC-request is delivered by several relayers for a low risk of data falsification. On the other hand, if a valid CCC-event is concurrently delivered to two different blockchains, user assets can increase or decrease on both sides. For example, when there are five relayers, the quorum is three. There can be a case where two relayers succeed and three fail in transmitting a CCC-event transaction that mints in Ethereum. In such a case, the “failed relayers” transmit a CCC-event transaction to the Bifrost Network, and the user is refunded in Ethereum. However, if one of the “failed relayers” re-sends the mint transaction and succeeds, the user’s asset in the Bifrost Network increases and results in “double payment.” This example shows how one malicious relayer can cause protocol failure.

Situations like the above can occur as the socket contract did not clearly finalize the CCC-event process result before proceeding to the next phase. Thus, a CCC-request must be finalized as one status in each phase before emitting an event. The relayer must proceed to the next phase only when a CCC-event of the next status is detected.

Each phase of the protocol delivers relay votes to the socket contract through one of the type methods described below. Moreover, for phases executing *f(x)* as a result of the relay vote, the “Self Transition Rule” additionally applies.

### Self Transition Rule (if fails)

For phases in which *f(x)* is executed, such as Inbound Phase1 or Outbound Phase2, the transaction may fail due to the logic of *f(x)* even if the relayers deliver valid CCC-events. However, as a failed transaction due to its atomic property cannot affect the socket contract, an “execution failure” CCC-event cannot be emitted. Thus, relayers set the CCC-event status to negative and transfer it to the socket contract. When the socket contract receives negative CCC-events from a majority of relayers, it emits the “execution failure” CCC-event and forces the process onto the next phase. (A negative status can never be restored to positive status.)

Furthermore, due to the transaction’s asynchronous property, we cannot know when the next status CCC-event is going to be emitted. There can be a situation where two out of five relayers emit a positive CCC-event, and the other two emit a negative CCC-event. If the remaining relayer does not act, this CCC-event can never be processed. This example shows how the protocol can fail due to one relayer.

Thus, relayers that have voted for positive status verify if the request has been finalized as a positive status after `t` seconds. If not finalized, the relayers change the original CCC-event to negative status and resend it. As a result, the CCC-event will always be processed in `t` seconds. (In the example case above, the status would ultimately be settled as negative.)

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FH8fQQeR8PesihgZ0uDH3%2FVariant%20Rule_%20Self%20Transition.png?alt=media&amp;token=cfb098d4-6714-4068-a5e6-41bd2db90f08" alt=""><figcaption></figcaption></figure>

**Figure Description**

1. Each relayer delivers the event of the detected positive status to the next socket contract.
   1. transaction success → set timer
   2. transaction failure → change event to negative status and resend it
2. timeout → change event to negative status and resend it

For each status, the socket contract executes *f(x)* at the `n`-th relay vote transaction that reaches the majority and emits the next CCC-event.

### Type 1: General Relay

**In the case of a phase with no f(x) in its resulting logic, each relayer simply delivers the CCC-event through a transaction.**

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FIVOFavsVgoapsNdvaRrJ%2FType%201_%20General%20Relay.png?alt=media&amp;token=5d25d868-8041-47d3-bf54-2b7782fc8000" alt=""><figcaption></figcaption></figure>

**Figure Description**

1. All relayers deliver the detected event to the next socket contract.

The socket contract emits the next CCC-event at the `n`-th relay vote transaction that reaches the majority.

#### Type 1-1: General Relay with signature

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2Fpjqtn5aoF0cplxBz46Ol%2FType%201-1_%20General%20Relay%20with%20signature.png?alt=media&amp;token=b92b0c07-df64-494d-ac2f-6b9d2041dbd3" alt=""><figcaption></figcaption></figure>

The relayer additionally attaches its signature to execute “Type 1: General Relay”. The socket contract saves the attached signatures, which can later be inquired en bloc by the socket contract.

### **Type 2: Aggregated Relay**

Instead of having all the relayers deliver the CCC-event to an external chain with a relatively high fee, one primary relayer aggregates all relayers’ signatures and emits a CCC-event. (Once the primary relayer is designated, other relayers are automatically considered secondary relayers.)

To ensure that the failure of the primary relayer does not lead to the failure of the protocol, secondary relayers verify whether or not the CCC-event has been successfully emitted after `t` seconds. If not emitted, all secondary relayers take on the role of the primary relayer and emit the CCC-event.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FbZGub8BBqMljJegSVmgo%2FType%202_%20Aggregated%20Relay.png?alt=media&amp;token=2851d542-4a6e-4257-8d94-2bdcb6cec2a7" alt=""><figcaption></figcaption></figure>

**Figure Description**

1. Calculate the primary relayer index: (the height of the block containing the event) % (the total number of validators). The relayer with the calculated primary relayer index is designated as the primary relayer. (The rest become secondary relayers.)
2. Primary relayer
   1. Inquires the socket contract for the relayers’ signature values submitted in the preceding phase.
   2. Attaches the majority number of signatures and delivers it to the next socket contract.
3. Secondary relayers
   1. If the primary relayer’s successful event delivery cannot be verified after `t` seconds, execute the primary relayer process instead.

The socket contract emits the next CCC-event upon verifying the majority of the signatures received.

## Applications

CCCP allows external chain users to use Bifrost Network DApp services. For example, let us say that *f(x)* is “Lending::Deposit” installed in the Bifrost Network. In this case, an Ethereum user can simply deposit tokens to the Ethereum socket contract, and this action will automatically deposit tokens to the lending service on the Bifrost Network. To give another example, let us say that *f(x)* is “Swap” in the Bifrost Network. In this case, a user can acquire some Bifrost Network’s token B by depositing some Ethereum’s token A through the inbound protocol, and then withdraw Avalanche’s token B through the outbound protocol. This implements a cross-chain swap.

Ultimately, the CCCP of the Bifrost Network allows users to enjoy DeFi services with relatively low fees and fast speed, and easily transfer assets between chains.


# Oracle Service

### Oracle Service Architecture

The Bifrost Network uses relayers to gather external oracle reports, which are validated and provided to the Bifrost ecosystem by oracle manager contracts. The process of collecting and distributing data through the Bifrost oracle service is illustrated in Figure 1.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FnVTQZSyEKQUyX3cHIIUX%2FBifrost%20Oracle%20Service%20Architecture.png?alt=media&amp;token=53969632-5a20-4189-b42d-bdaab172b185" alt=""><figcaption><p>Figure 1. BIFROST Oracle Service Architecture</p></figcaption></figure>

#### Data Collection

Relayers on the Bifrost Network are responsible for collecting readings from various sources, both on-chain and off-chain, based on the configuration of the oracle. They then submit this data to the oracle manager contract for validation and distribution within the Bifrost ecosystem.

#### Two Types of Data

The Bifrost oracle service supports two types of data: exact data, such as the block hash of the latest Bitcoin block, and aggregatable data, such as token prices. For exact data, the oracle manager contract verifies that a quorum of relayers has submitted the same report. For aggregatable data, the oracle manager calculates the average of the submitted reports after eliminating outliers.

#### Data Feed

An oracle manager is a smart contract that serves as a data feed in the Bifrost Network. It verifies and processes data from multiple sources, then provides the final results along with metadata, such as the collection round number, to ensure the timeliness and reliability of the report.

### Features

#### Source-specific Collection

Relayers may be configured to follow different approaches in the data collection process, including the triggers for collection and post-processing procedures, depending on the specific data sources being utilized.

Token prices are regularly collected from both centralized and decentralized exchanges, and outliers are removed through price deviation verification during post-processing. The collection of Bitcoin block hashes, on the other hand, is triggered by new block notifications. In the event of an unexpected chain reorganization in Bitcoin, relayers can correct obsolete block hashes during the post-processing step.

#### Price Aggregation and Correction

Relayers combine prices from centralized and decentralized exchanges and adjust them to reflect market conditions more accurately. A volume-weighted average is calculated for prices from centralized exchanges, as the daily trading volume is known. Prices from decentralized exchanges are averaged without considering trading volume but are used to improve the volume-weighted average by taking the median between the two average values.

#### Reorg-aware Bitcoin Post-processing

In Bitcoin, there is a risk of unexpected large-scale block reorganization events occurring. To address this, we designed the committed value storage in the oracle manager contract to be adjustable when relayers resubmit the updated hash values of reorganized blocks.

#### Easy DApp Integration

Chainlink is the most widely-used blockchain oracle service. To minimize the learning curve for using Bifrost's oracle service, it offers an interface compatible with that of Chainlink. As a result, DApp developers can utilize our oracle service without the need to acquire additional knowledge.


# Running a Node

Anyone can become a validator or nominator by depositing BFC into the BIFROST Network. Validators generate new blocks and verify blocks generated by other validators in the set. Active validators receive rewards at the end of each round for performing these tasks correctly. In every round of block generation, validator candidates are ranked based on the sum of their self-bonded stake and delegated deposits from their nominators. The top *n* candidates in the ranking become active validators that can participate in the consensus process in the next round to earn rewards.

### Two-tier Node Architecture

Nodes of the BIFROST Network are similar to typical Substrate-based nodes, but the interoperability nature of the network also requires some additional features. Thus, the BIFROST Network consists of two-tier nodes:

**Basic node** of the first tier plays the role of block producing and acts as an archive node. Basic nodes are typical Substrate-based nodes.

**Full-node** of the second tier has the features of the basic node and additionally plays the role of a relayer that interconnects blockchains.&#x20;

| Node Tier  | Feature Requirements                                                                                                                                   |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Basic node | <p>- Block production / Finalization (AURA / GRANPA)<br>- Archive mode</p>                                                                             |
| Full node  | <p>- Block production / Finalization (AURA / GRANPA)<br>- Archive mode<br>- Cross-chain relaying<br>- Price feed collection (on-chain / off-chain)</p> |

### "Controller" and "Stash" Keys <a href="#controller-and-stash-keys" id="controller-and-stash-keys"></a>

Two types of accounts are required to run a validator (both full node and basic node), as well as to become a nominator – "Controller" and "Stash" accounts. They are distinguished by their intended use, not by an underlying cryptographic difference.

#### Controller Key

The controller key is a semi-online key that will be in the direct control of a user and used to submit manual extrinsics. For validators or nominators, this means that the controller key will be used to start or stop validating or nominating. Controller keys should hold some BFC to pay for fees, but they should not be used to hold huge amounts or life savings. Since they will be exposed to the internet with relative frequency, they should be treated carefully and occasionally replaced with new ones.

#### Stash Key

The stash key is a key that will, in most cases, be a cold wallet, existing on a piece of paper in a safe or protected by layers of hardware security. It should rarely, if ever, be exposed to the internet or used to submit extrinsics. The stash key is intended to hold large amounts of funds. It should be thought of as a savings account at a bank, which is ideally only ever touched in urgent conditions. Or, perhaps a more apt metaphor is to think of it as buried treasure, hidden on some random island and only known by the pirate who originally hid it.

Since the stash key is kept offline, it must be set to have its funds bonded to a particular controller. For non-spending actions, the controller has the funds of the stash behind it. For example, in nominating, staking, or voting, the controller can indicate its preference with the weight of the stash. It will never be able to actually move or claim the funds in the stash key. However, if someone does obtain your controller key, they could use it for slashable behavior, so you should still protect it and change it regularly.


# Basic-Node Requirements

Basic node operators stake BFC to verify and create blocks. Validators should expect staking rewards if they stake in the network for at least three months. The longer the staking period, the higher the rewards. The rewards consist of:

* Self-staking rewards which accrue in proportion to the number of staked tokens
* Transaction fees
* A portion of nominators' staking rewards (optional)

## Technical Requirements

#### Hardware

{% tabs %}
{% tab title="Testnet" %}

<table><thead><tr><th width="239">Resource</th><th>Minimum</th><th>Recommended</th></tr></thead><tbody><tr><td>CPU</td><td>4 cores</td><td>8+ cores</td></tr><tr><td>RAM</td><td>8 GB</td><td>16+ GB</td></tr><tr><td>Disk</td><td>500 GB</td><td>1+ TB</td></tr></tbody></table>
{% endtab %}

{% tab title="Mainnet" %}

<table><thead><tr><th width="239">Resource</th><th>Minimum</th><th>Recommended</th></tr></thead><tbody><tr><td>CPU</td><td>4 cores</td><td>8+ cores</td></tr><tr><td>RAM</td><td>16 GB</td><td>32+ GB</td></tr><tr><td>Disk</td><td>1.5+ TB</td><td>2+ TB</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

## Bonding Requirements

{% tabs %}
{% tab title="Testnet" %}

| Requirements                                           | Amount     |
| ------------------------------------------------------ | ---------- |
| Minimum self-bond                                      | 50,000 BFC |
| Minimum voting power (self-bond + total nominated BFC) | 50,000 BFC |

{% endtab %}

{% tab title="Mainnet" %}

| Requirements                                           | Amount        |
| ------------------------------------------------------ | ------------- |
| Minimum self-bond                                      | 400,000 BFC   |
| Minimum voting power (self-bond + total nominated BFC) | 2,000,000 BFC |
| {% endtab %}                                           |               |
| {% endtabs %}                                          |               |

## Operating Performance Standards

To guarantee network stability and fast finality, all node operators are required to meet the published hardware specifications.

### Actionable Warning for Validators

Effective immediately, Validator-Nodes must be capable of consistently performing block creation within a **3-second** timeframe (the target block time). Validators who fail to maintain this performance standard due to inadequate hardware will be subject to monitoring and have a possibility of being penalized (slashed).

To avoid penalties and ensure optimal block creation performance, your setup must meet or exceed the requirements above.

## Operating Requirements

### Account Management

Validators should securely manage two accounts, Stash and Controller accounts, for self-bonding deposit and consensus participation, respectively.

* Stash account: An EVM account for the self-bonding deposit.
* Controller account: An EVM account for consensus participation. It should have enough balance for transaction fees used in certain operations.

### Required Credentials

Validators require three types of keys as follows:

* AURA key for block production
* GRANDPA key for block finalization
* “Imonline” key to check the node availability


# Full-Node Requirements

Full nodes share all the features of the basic nodes and additionally facilitate Cross-Chain Communication. To do that, they must keep access to external blockchains and off-chain data feed for price oracles. Full node rewards consist of:

* Self-staking rewards which accrue in proportion to the number of staked tokens
* Transaction fees
* Fees from cross-chain transactions
* A portion of nominators' staking rewards (optional)

## Technical Requirements

#### Hardware

{% tabs %}
{% tab title="Testnet" %}

<table><thead><tr><th width="239">Resource</th><th>Minimum</th><th>Recommended</th></tr></thead><tbody><tr><td>CPU</td><td>4 cores</td><td>8+ cores</td></tr><tr><td>RAM</td><td>16 GB</td><td>32+ GB</td></tr><tr><td>Disk</td><td>500 GB</td><td>1+ TB</td></tr></tbody></table>
{% endtab %}

{% tab title="Mainnet" %}

<table><thead><tr><th width="239">Resource</th><th>Minimum</th><th>Recommended</th></tr></thead><tbody><tr><td>CPU</td><td>4 cores</td><td>8+ cores</td></tr><tr><td>RAM</td><td>16 GB</td><td>32+ GB</td></tr><tr><td>Disk</td><td>1.5+ TB</td><td>2+ TB</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

## Bonding Requirements

{% tabs %}
{% tab title="Testnet" %}

| Requirements                                           | Amount      |
| ------------------------------------------------------ | ----------- |
| Minimum self-bond                                      | 100,000 BFC |
| Minimum voting power (self-bond + total nominated BFC) | 100,000 BFC |
| {% endtab %}                                           |             |

{% tab title="Mainnet" %}

| Requirements                                           | Amount        |
| ------------------------------------------------------ | ------------- |
| Minimum self-bond                                      | 400,000 BFC   |
| Minimum voting power (self-bond + total nominated BFC) | 4,000,000 BFC |
| {% endtab %}                                           |               |
| {% endtabs %}                                          |               |

## Operating Performance Standards

To guarantee network stability and fast finality, all node operators are required to meet the published hardware specifications.

### Actionable Warning for Validators

Effective immediately, Validator-Nodes must be capable of consistently performing block creation within a **3-second** timeframe (the target block time). Validators who fail to maintain this performance standard due to inadequate hardware will be subject to monitoring and have a possibility of being penalized (slashed).

To avoid penalties and ensure optimal block creation performance, your setup must meet or exceed the requirements above.

## Operating Requirements

### Account Management

Validators should securely manage three accounts, Stash, Controller, and Relayer accounts, for self-bonding deposit and consensus participation, respectively.

* Stash account: An EVM account for the self-bonding deposit.
* Controller account: An EVM account for consensus participation. It should have enough balance for transaction fees used in operations.
* Relayer account: An EVM account for cross-chain action participation. It should have enough balance for transaction fees used in operations.

### Required Credentials

Validators require three types of keys as follows:

* AURA key for block production
* GRANDPA key for block finalization
* “Imonline” key to check the node availability

### External Source Access

Full nodes should set up Web3 providers to all the external blockchains supported by the Bifrost Network via reusing their blockchain RPC nodes or employing external services (e.g. Infura or NodeReal).

#### Price Feed

The full-node validators collect on-chain and off-chain data for price oracles.

* On-chain price feed: ChainLink
* Off-chain API: CoinGecko, Upbit, Binance, Gate.io, Kucoin


# Validator Account Management

## Time-related parameters

In the Bifrost Network, there are several parameters related to time with which node operators need to be familiar. You must familiarize yourself with these parameters prior to account management.

{% tabs %}
{% tab title="Testnet" %}

| Parameter              | Value                       |
| ---------------------- | --------------------------- |
| Round duration         | 6 hours                     |
| Session duration       | 15 minutes                  |
| Bond less delay        | 2 rounds (Approx. 12 hours) |
| Leave candidates delay | 2 rounds (Approx. 12 hours) |
| {% endtab %}           |                             |

{% tab title="Mainnet" %}

| Parameter              | Value                      |
| ---------------------- | -------------------------- |
| Round duration         | 12 hours                   |
| Session duration       | 15 minutes                 |
| Bond less delay        | 14 rounds (Approx. 7 days) |
| Leave candidates delay | 14 rounds (Approx. 7 days) |
| {% endtab %}           |                            |
| {% endtabs %}          |                            |

## Polkadot.js account setup

Validator node operators must deposit self-bonds through their stash accounts to operate the nodes. In some cases, the deposited BFC may be withdrawn, and additional deposits may need to be made. To perform these actions, node operators must utilize the administrator page provided by Polkadot which can be accessed via the following link.

| Testnet                                                                                                          | Mainnet                                                                                                           |
| ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| [polkadot.js/apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpublic-01.testnet.thebifrost.io%2Fws#/explorer) | [polkadot.js/apps](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpublic-01.mainnet.thebifrost.io%2Fwss#/explorer) |

Upon accessing the link, a page similar to the image below will show up.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FuokQfMnoRyOyXcNUeflQ%2Fimage.png?alt=media&amp;token=f3025c86-1aa0-4e0a-a906-75e6f76b6e6d" alt=""><figcaption></figcaption></figure>

Upon successful access, you must register your stash and controller account that is currently being used for your validator node activities on the page. First, click on the "Add account" button located near the center of the page.

{% hint style="info" %}
If the "Add account" button does not show up or as disabled, then access the "Settings" tab and set the "in-browser account creation" option to "Allow local in-browser account storage". This option will allow to store your accounts to your local web browser.
{% endhint %}

Click on the button to switch to the next page. Then, enter the secret key or mnemonic seed of the account in the input box, check the check box at the bottom, and click on the "Next" button to continue.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FjPvx7HlOb5CnUcO6GGTg%2FUntitled.png?alt=media&amp;token=5289255f-0f9e-4424-9da8-dc170d7cc7e7" alt=""><figcaption></figcaption></figure>

On the next page, you must enter the name and password of the account you wish to register. As the name of the account does not affect the system in any way and is visible only in your local environment, set it to a name that is easily recognizable. Also, as the password must be entered once for verification before transaction transmission through the polkadot.js app page, make sure to store it safely. Once you have entered all the information, click on the "Next" button to proceed to the next step.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F0jMrBJWY3TeUtMy12DRj%2FUntitled%20(1).png?alt=media&amp;token=c45dc0e9-adf5-495f-bdd9-0288bde6866c" alt=""><figcaption></figcaption></figure>

On the next page, you can create a backup file for the account you wish to register. The backup file is in JSON format, and with this, you can restore your account if necessary by clicking on the "Restore JSON" button located in the center of the "Accounts" page. Clicking on the "Next" button closes the window and the backup file will be downloaded. Once all processes have been completed, you will be able to check that the registered account has been added to the "accounts" list.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2Fv39aO8ppUZAWzYGlCAvB%2FUntitled%20(2).png?alt=media&amp;token=360229e4-7a22-4467-bc97-c85a056e31fb" alt=""><figcaption></figcaption></figure>

All processes specified above must be performed once each for the stash account and controller account.

## Self-Bond Management

Validator node operators can access and manage their own self-bonds. This means that if you completely own the stash and controller accounts in use, you can make additional deposits or withdrawals.

### Bond More

In order to proceed with the additional deposit, your stash account must be registered on the polkadot.js app page in advance, and the account must hold enough BFC for the additional deposit you wish to make.

First, click on the "Developer" tab at the top and access the "Extrinsic" page.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FJPj5xIgZbK8EOnAkaBJL%2FUntitled%20(3).png?alt=media&amp;token=e8b4ff75-93e6-44c5-8321-eca315af6049" alt=""><figcaption></figcaption></figure>

When you move to the link, you will see the following page. Proceed with the following steps in order.

1. Select your own stash account.
2. Select the "bfcStaking" pallet.
3. Select the "candidateBondMore" extrinsic.
4. Enter the amount of BFC you want to deposit in Wei units. If you want to deposit 100 BFC, you must add 18 zeros to 100.
5. Click on the "Submit Transaction" button.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FbHwAgYoQcvkA4kiI8tWd%2FUntitled%20(4).png?alt=media&amp;token=cf1be1ae-0a8b-479d-9ebf-5f3f19a77d2a" alt=""><figcaption></figcaption></figure>

If you enter the account password and click on the "Sign and Submit" button at the bottom, the transaction will be sent and the additional deposit result will be immediately reflected.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FzQzjljDHmVrPMkwn4elb%2FUntitled%20(5).png?alt=media&amp;token=333e80fa-7f1d-40a9-a9e4-b36353e48ca3" alt=""><figcaption></figcaption></figure>

The reflected result can be found on the next [page](https://thebifrost.io/network/stake).

### Bond Less

To proceed with partial withdrawal, both your stash account and controller account must be registered on the polkadot.js app page in advance. The entire withdrawal process consists of two stages. First, you must perform the "Schedule Withdrawal" process with the controller account. At this time, even if the request is successfully processed, the withdrawal cannot be executed immediately. You must wait for a certain number of rounds. ("Bond less delay") If you have finished waiting, you must finally execute the "Execute withdrawal" process with your stash account to complete the actual withdrawal. All actions are performed on the "Extrinsic" page under the "Developer" tab.

#### Schedule Bond Less

1. Select your own controller account.
2. Select the "bfcStaking" pallet.
3. Select the "scheduleCandidateBondLess" extrinsic.
4. Enter the amount of BFC to be partially withdrawn in Wei units. If you want to withdraw 100 BFCs, you must add 18 zeros to 100.
5. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FbGaW5PxtJ59SQhP1YQT2%2FUntitled%20(6).png?alt=media&amp;token=cba90f23-bb2c-432d-855b-73b43b9bb0c8" alt=""><figcaption></figcaption></figure>

#### **Cancel Schedule Bond Less**

You can also cancel the withdrawal request made in advance. In the case of cancellation, calls can be made regardless of delays.

1. Select your own controller account.
2. Select the "bfcStaking" pallet.
3. Select the "cancelCandidateBondLess" extrinsic.
4. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FFmEqr43AHjg8xx0eGm86%2FUntitled%20(7).png?alt=media&amp;token=29217e1a-34b6-433c-88a5-a9393b1d961c" alt=""><figcaption></figcaption></figure>

#### **Execute Bond Less**

1. Select your own stash account.
2. Select the "bfcStaking" pallet.
3. Select the "executeCandidateBondLess" extrinsic.
4. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FyIKUrrTcLkkaPUabXxYX%2FUntitled%20(8).png?alt=media&amp;token=0871bab6-5484-4a36-b695-8615d7f45422" alt=""><figcaption></figcaption></figure>

### Leave Validators

If you wish to quit your validator activity and leave, your stash account and controller account must be registered on the polkadot.js app page in advance. If you choose to leave, all deposited self-bond will be returned to your stash account, and all nominations will also be returned to the nominators.

The entire process of exit consists of two steps, as with partial withdrawal. You must first perform the "Schedule Leave" process with the controller account. At this time, even if the request is successfully processed, exit cannot be immediately executed. You must wait for a certain number of rounds. ("Leave candidates delay") If you have finished waiting, you must finally perform the "Execute Leave" process with your stash account to complete the actual exit.

If a validator node operation is terminated without proceeding to exit, a penalty may be applied and some of your assets may be deducted. Therefore, be aware of this process to exit and guard your assets safely.

#### **Schedule Leave**

1. Select your own controller account.
2. Select the "bfcStaking" pallet.
3. Select the "scheduleLeaveCandidates" extrinsic.
4. Enter the current number of validators. If the value is greater than or equal to the current number of validators, it will operate normally.
5. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FEhD1spDijjVsFfVYvOoC%2FUntitled%20(9).png?alt=media&amp;token=a4609d3f-2105-4c2b-b3e0-9881c1babfb8" alt=""><figcaption></figcaption></figure>

#### **Cancel Schedule Leave**

You can also cancel the request for leave in advance. In the case of cancellation, calls can be made regardless of the delay.

1. Select your own controller account.
2. Select the "bfcStaking" pallet.
3. Select the "cancelLeaveCandidates" extrinsic.
4. Enter the current number of validators. If the value is greater than or equal to the current number of validators, it will operate normally.
5. Click on the "Submit Transaction" button and send the transaction through password entry and signature.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FQZWxCF2Q0svDb4WwzS70%2FUntitled%20(10).png?alt=media&amp;token=931d4fdc-7ded-4414-8219-4fcbabc4e150" alt=""><figcaption></figcaption></figure>

#### **Execute Leave**

1. Select your own stash account.
2. Select the "bfcStaking" pallet.
3. Select the "executeLeaveCandidates" extrinsic.
4. Enter the number of nominators nominated for yourself. If the value is greater than or equal to the current number of nominators, it operates normally.
5. Click on the "Submit Transaction" button and send the transaction through password entry and signature.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2Fmg4IbcX13m0YllfoR8KU%2FUntitled%20(11).png?alt=media&amp;token=079a0636-b825-4224-8530-c4e42893fbd1" alt=""><figcaption></figcaption></figure>

If you have finished executing the exit, you may completely shut down the validator node that was in operation.

## Set Auto-Compound Destination

The Bifrost Network provides Auto-Compounding functionality. This optional feature allows both validators and nominators to decide whether to receive their round rewards in their wallets ("Account") or to immediately add them to their stakes ("Staked").

The “Account” option receives round rewards paid in each round to the wallet you deposited. In this case, there is no change in one's self-bond, and the token paid can be used immediately in the wallet without a special lock.

The “Staked” option automatically makes an additional deposit immediately to your self-bond for the round reward you receive for each round. It is set to the default value of all network participants (validators + nominators).

Proceed with the following steps in order.

1. Select your own controller account.
2. Select the "bfcStaking" pallet.
3. Select the "setCandidateRewardDst" extrinsic.
4. Select the "Staked" or "Account" option.
5. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FGJ87Yil64IM3Ss6ZbR6d%2FUntitled%20(12).png?alt=media&amp;token=59c2a13f-7ed4-46b9-9db1-1538a5a603ef" alt=""><figcaption></figcaption></figure>

## Set Commission Rate

All validators are able to set a commission rate according to their tier.

{% tabs %}
{% tab title="Testnet" %}

| Tier         | Rate Range                |
| ------------ | ------------------------- |
| Full Node    | 0% \~ 100% (default: 50%) |
| Basic Node   | 0% \~ 20% (default: 10%)  |
| {% endtab %} |                           |

{% tab title="Mainnet" %}

| Tier          | Rate Range                |
| ------------- | ------------------------- |
| Full Node     | 0% \~ 100% (default: 30%) |
| Basic Node    | 0% \~ 20% (default: 10%)  |
| {% endtab %}  |                           |
| {% endtabs %} |                           |

Proceed with the following steps in order.

1. Select your own controller account.
2. Select the "bfcStaking" pallet.
3. Select the "setValidatorCommission" extrinsic.
4. Enter the rate you want to change. For example, if you wish to change it to 60%, you must add 7 zeros to 60.
5. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FbaI2ieOpg34fDjwOhNF6%2F6.png?alt=media&amp;token=75a1844d-1b90-448e-ba80-98972d97438c" alt=""><figcaption></figcaption></figure>

If you wish to pause your validator activity for a certain period of time without unbonding your self-bonds, you can change your node status to offline. When switching to offline status, you should be familiar with the following.

* Self-bonds and nominations are not withdrawn and will remain.
* Additional deposits and partial withdrawals of your self-bond, and nominations will be possible.
* You can leave the validator set only after switching back to online status.
* You cannot be selected as an active validator during the round update.
* When you change your status to offline while operating as an active validator, you will still be paid for your active share.
* As the offline request is reflected after one session, at least one session must be kept online to prevent any penalties.

Proceed with the following steps in order.

1. Select your own controller account.
2. Select the "bfcStaking" pallet.
3. Select the "goOffline()" extrinsic.
4. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FWJAetaZis10HWc7lVAn0%2F7.png?alt=media&amp;token=48aca924-acf1-4c08-88fa-2e3065607739" alt=""><figcaption></figcaption></figure>

## Set Validator Online

If a node in operation has switched to offline status, or has been removed from the round due to continuous inactivity without an offline request, the node must be switched back to online status to proceed with normal validator activity. If not, the validator will not be selected as an active validator.

Proceed with the following steps in order.

1. Select your own controller account.
2. Select the "bfcStaking" pallet.
3. Select the "goOnline()" extrinsic.
4. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FDBj5dhk4jhJiLftS1nmC%2FUntitled.png?alt=media&amp;token=f95de1dc-55b1-4180-b07e-86fc89cee103" alt=""><figcaption></figcaption></figure>

## Set Validator Tier

It is possible to change the tier of the node in operation. When changing from the basic node to the full node, the following conditions must be satisfied.

* Additional deposits must be made if the minimum required amount of self-bonds is not met.
* A new Ethereum account is required for relayer operation.
* A relayer must be operated after changing the tier.

Proceed with the following steps in order.

1. Select your own stash account.
2. Select the "bfcStaking" pallet.
3. Select the "setValidatorTier()" extrinsic.
4. If an additional deposit of self-bonds is required, enter the BFC amount in wei units in the `more` parameter. Otherwise, enter 0.
5. Select the tier of the node to which you wish to change. (Select `Full` or `Basic`)
6. Select the relayer account when changing to a full node. If not, toggle the "include option" button located on the right to disabled.
7. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

If the modification has successfully been processed, your tier will be updated as the one you have selected. But your node will still be operating as the previous tier until the current round ends.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2Fyyo9kAEz5UHkMLFpAvaY%2FUntitled.png?alt=media&amp;token=fc66df35-f2db-4f86-846d-fc43d09bb083" alt=""><figcaption></figcaption></figure>

## (Re-)Set Controller Account

Since controller accounts for each validator is public to the network due to validator activities, there could be a chance that an attacker exploits or takeover your account. Although, since validator accounts are divided to multiple accounts, the attacker won't be able to withdraw your self-bonds. But for future safety we suggest to let exposed controller accounts to be replaced. To do so, the following conditions must be satisfied.

* A new controller account must be prepared contained with some funds for transaction payments. This new account will later be replaced from your previous account.
* Double check if your previous account has any leftover funds. If so transfer to any other safe account.

Now to (re-)set your controller account, proceed with the following steps in order.

1. First, access to your `tools` directory that was used to setup your validator node.
2. Execute the `set_session_keys` CLI command to register a new set of on-chain session keys. At this point, the `controllerPrivate` option must be your new accounts private key.
3. Now, access the polkadot.js web page and move on to the extrinsics tab. In prior, your new account must be registered to polkadot.js
4. Select your own stash account.
5. Select the "bfcStaking" pallet.
6. Select the "setController()" extrinsic.
7. Set the `new` parameter to your new account.
8. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FmwCpKYiMlwL8aUKJWpGx%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-11-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.18.35.png?alt=media&amp;token=b6cb8f57-cb2a-4ae1-aa32-081f5261a0c1" alt=""><figcaption></figcaption></figure>

After the transaction has been successfully executed, the actual account replacement (state change) will be applied at the beginning of the next round.

## (Re-)Set Relayer Account

In case of full node operators, your relayer account can be replaced. To do so, the following conditions must be satisfied.

* A new relayer account must be prepared contained with enough funds for cross-chain actions. This new account will later be replaced from your previous account.
* Double check if your previous account has any leftover funds. If so transfer to any other safe account.

Now to (re-)set your relayer account, proceed with the following steps in order.

1. First, access the polkadot.js web page and move on to the extrinsics tab. In prior, your new account must be registered to polkadot.js
2. Select your own controller account.
3. Select the "relayManager" pallet.
4. Select the "setRelayer()" extrinsic.
5. Set the `new` parameter to your new account.
6. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FXXNBzSLVTvChYjf8ELGO%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-11-25%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.40.48.png?alt=media&amp;token=50646a75-ff9e-4402-90e4-8266f07df5c7" alt=""><figcaption></figcaption></figure>

After the transaction has been successfully executed, the actual account replacement (state change) will be immediately applied. Due to the replacement, your running relayer program's account setup must be modified as well.


# Relayer Management


# Relay Executives: Keystore Migration

This guide outlines the steps to migrate your local keystore to the new encryption and decryption mechanism.

🔹 **If you do not have a keystore configured, you can skip this section.**

Due to differences between relayer client versions, the migration steps may vary depending on your current version. To check your client version, run the following command:

```sh
./bifrost-relayer --version
```

Example Output:

```sh
bifrost-relayer 2.1.1-1b4f8ca012b
```

## 1. For Relayer Client versions below v2.1.1

### 1.1. Binary Update

To migrate your keystore, follow the steps below to update your relayer client to the latest version:

**Step 1.**

Remove or create a backup of the previous `bifrost-relayer` binary file before proceeding.

```sh
rm <PATH_TO_BIFROST_RELAYER_BINARY>
```

**Step 2.**

Install the latest version of `bifrost-relayer` in the same directory and update the necessary permissions. *(Note: If the directory has changed, be sure to update the Systemd configuration file accordingly)*

```sh
wget "https://github.com/bifrost-platform/bifrost-relayer.rs/releases/latest/download/bifrost-relayer"
chmod +x bifrost-relayer
```

### 1.2. Configuration Update

#### 1.2.1. Signer Configurations

The method for specifying and configuring the signer has changed. Previously, it was configured as follows:

```yaml
system:
  private_key: "0xxxx...xxx"
```

However, the configuration has now changed. The private key from the system section has been removed. Instead, you must explicitly specify a `signer_config`, which can contain either:

* A plaintext private key
* An AWS KMS key

Below is the updated configuration format:

```yaml
system:
  # -----> ❌ Private key removed from here

# Option 1. When using AWS KMS signer
signer_config:
  - kms_key_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Option 2. When using local signer with plaintext private key
signer_config:
  - private_key: "0xxxx...xxx"
```

#### 1.2.2. Keystore Configurations

The method for specifying and configuring the keystore has changed. Previously, it was configured as follows:

```yaml
system:
  keystore_path: "./example"
  keystore_password: "password"
```

However, the configuration has now changed. The path and password from the system section have been removed. Instead, you must explicitly specify a `keystore_config`, which includes:

* The keystore path
* Either a plaintext password or an AWS KMS key
  * ⚠️ **Important:** At this step, you **must enter your previously used password** to proceed with the migration.

Below is the updated configuration format:

```yaml
system:
  # -----> ❌ path and password removed from here

keystore_config:
  path: "./example"
  password: "password"  # -----> ⚠️ Important: Enter your previously used password
```

### 1.3. Run the Migration CLI Command: `migrate-keystore`

Before proceeding with the migration, you have to first stop the running relayer. To do so, run the following command:

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl stop bifrost-relayer.service
```

#### 1.3.1. Fetch the latest BRP Round

And then, you need to fetch the **latest BRP (Bitcoin Relay Protocol) round**. To do so, run the following command:

**Mainnet**

```sh
curl --location 'https://public-01.mainnet.bifrostnetwork.com/rpc' --header 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":0,"method":"eth_call","params":[{"to":"0x0000000000000000000000000000000000000100","data":"0x319c068c"}]}'
```

Example Output:

```json
{
    "jsonrpc": "2.0",
    "result": "0x0000000000000000000000000000000000000000000000000000000000000002",
    "id": 0
} # -----> ✅ The latest round is 2
```

**Testnet**

```sh
curl --location 'https://public-01.testnet.bifrostnetwork.com/rpc' --header 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":0,"method":"eth_call","params":[{"to":"0x0000000000000000000000000000000000000100","data":"0x319c068c"}]}'
```

Example Output:

```json
{
    "jsonrpc": "2.0",
    "result": "0x0000000000000000000000000000000000000000000000000000000000000001",
    "id": 0
} # -----> ✅ The latest round is 1
```

Now you have two options for migrating your keystore encryption:

1. **Keystore encrypted by a plaintext password**
2. **Keystore encrypted by AWS KMS**

Choose the option that best fits your security requirements and follow the corresponding steps.

#### 1.3.2. Option 1: **Password Encrypted Keystore**

To migrate your keystore, run the following command with the necessary options:

* chain: Specify the path to your config.yaml file.
* round: Enter the round index you fetched in the previous step.
* new-password: Set a new plaintext password for encrypting and decrypting keystore keys.
  * 🚨 **We highly recommend using a new password for better security.**
* version: This option must be set to 1 at this step.

⚠️ **Important:** Before running the command, your previously used password must be specified in the config.yaml file for the migration to succeed.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
./bifrost-relayer migrate-keystore \
    --chain "<YOUR_CONFIG_YAML_FILE_PATH>" \
    --round <THE_POOL_ROUND_TO_MIGRATE> \
    --new-password "<YOUR_NEW_PASSWORD>" \
    --version 1
```

If the command successfully worked, replace `keystore_config.password` with your newly set password in the config.yaml file.

```sh
keystore_config:
  path: "./example"
  password: "new-password"  # -----> Replace this to your new password
```

Now it’s fully set to go. You can now restart your relayer.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl restart bifrost-relayer.service
```

#### 1.3.3. Option 2: AWS KMS Encrypted Keystore

To migrate your keystore, run the following command with the necessary options:

* `chain`: Specify the path to your config.yaml file.
* `round`: Enter the round index you fetched in the previous step.
* `new-kms-key-id`: Set a new AWS KMS key ID for encrypting and decrypting keystore keys.
* `version`: This option must be set to 1 at this step.

⚠️ **Important:** Before running the command, your previously used password must be specified in the config.yaml file for the migration to succeed.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
./bifrost-relayer migrate-keystore \
    --chain "<YOUR_CONFIG_YAML_FILE_PATH>" \
    --round <THE_POOL_ROUND_TO_MIGRATE> \
    --new-kms-key-id "<YOUR_NEW_KMS_KEY_ID>" \
    --version 1
```

If the command successfully worked, remove `keystore_config.password` and add `keystore_config.kms_key_id`, then set it to your new AWS KMS key ID in the config.yaml file.

```yaml
keystore_config:
  path: "./example"
  kms_key_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  # -----> Remove password and add kms_key_id
```

Now it’s fully set to go. You can now restart your relayer.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl restart bifrost-relayer.service
```

## 2. For Relayer Client versions higher than or equal to v2.1.1

### 2.1. Binary Update

To migrate your keystore, follow the steps below to update your relayer client to the latest version:

**Step 1.**

Remove or create a backup of the previous `bifrost-relayer` binary file before proceeding.

```sh
rm <PATH_TO_BIFROST_RELAYER_BINARY>
```

**Step 2.**

Install the latest version of `bifrost-relayer` in the same directory and update the necessary permissions. *(Note: If the directory has changed, be sure to update the Systemd configuration file accordingly)*

```sh
wget "https://github.com/bifrost-platform/bifrost-relayer.rs/releases/latest/download/bifrost-relayer"
chmod +x bifrost-relayer
```

### 2.2. Run the Migration CLI Command: `migrate-keystore`

Before proceeding with the migration, you have to first stop the running relayer. To do so, run the following command:

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl stop bifrost-relayer.service
```

#### 2.2.1. Fetch the latest BRP Round

And then, you need to fetch the **latest BRP (Bitcoin Relay Protocol) round**. To do so, run the following command:

**Mainnet**

```sh
curl --location 'https://public-01.mainnet.bifrostnetwork.com/rpc' --header 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":0,"method":"eth_call","params":[{"to":"0x0000000000000000000000000000000000000100","data":"0x319c068c"}]}'
```

Example Output:

```json
{
    "jsonrpc": "2.0",
    "result": "0x0000000000000000000000000000000000000000000000000000000000000002",
    "id": 0
} # -----> ✅ The latest round is 2
```

**Testnet**

```sh
curl --location 'https://public-01.testnet.bifrostnetwork.com/rpc' --header 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":0,"method":"eth_call","params":[{"to":"0x0000000000000000000000000000000000000100","data":"0x319c068c"}]}'
```

Example Output:

```json
{
    "jsonrpc": "2.0",
    "result": "0x0000000000000000000000000000000000000000000000000000000000000001",
    "id": 0
} # -----> ✅ The latest round is 1
```

Now you have two options for migrating your keystore encryption:

1. **Keystore encrypted by a plaintext password**
2. **Keystore encrypted by AWS KMS**

Choose the option that best fits your security requirements and follow the corresponding steps.

#### 2.2.2. Option 1: **Password Encrypted Keystore**

To migrate your keystore, run the following command with the necessary options:

* `chain`: Specify the path to your config.yaml file.
* `round`: Enter the round index you fetched in the previous step.
* `new-password`: Set a new plaintext password for encrypting and decrypting keystore keys.
  * 🚨 **We highly recommend using a new password for better security.**

⚠️ **Important:** Before running the command, your previously used password or AWS-KMS key ID must be specified in the config.yaml file for the migration to succeed.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
./bifrost-relayer migrate-keystore \
    --chain "<YOUR_CONFIG_YAML_FILE_PATH>" \
    --round <THE_POOL_ROUND_TO_MIGRATE> \
    --new-password "<YOUR_NEW_PASSWORD>"
```

If the command successfully worked, update your config.yaml file as follows:

* If you previously had `keystore_config.password`, replace it with your newly set password.
* If you previously had `keystore_config.kms_key_id`, remove it and add `keystore_config.password`, then set it to your new password.

```yaml
keystore_config:
  path: "./example"
  password: "new-password"  # -----> Add or replace this to your new password
```

Now it’s fully set to go. You can now restart your relayer.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl restart bifrost-relayer.service
```

#### 2.2.3. Option 2: AWS KMS Encrypted Keystore

To migrate your keystore, run the following command with the necessary options:

* `chain`: Specify the path to your config.yaml file.
* `round`: Enter the round index you fetched in the previous step.
* `new-kms-key-id`: Set a new AWS KMS key ID for encrypting and decrypting keystore keys.

⚠️ **Important:** Before running the command, your previously used password or AWS-KMS key ID must be specified in the config.yaml file for the migration to succeed.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
./bifrost-relayer migrate-keystore \
    --chain "<YOUR_CONFIG_YAML_FILE_PATH>" \
    --round <THE_POOL_ROUND_TO_MIGRATE> \
    --new-kms-key-id "<YOUR_NEW_KMS_KEY_ID>"
```

If the command successfully worked, update your config.yaml file as follows:

* If you previously had `keystore_config.kms_key_id`, replace it with your newly set key ID.
* If you previously had `keystore_config.password`, remove it and add `keystore_config.kms_key_id`, then set it to your new key ID.

```yaml
keystore_config:
  path: "./example"
  kms_key_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  # -----> Add or replace this to your new key ID
```

Now it’s fully set to go. You can now restart your relayer.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl restart bifrost-relayer.service
```


# Relayer Account Update

This guide will walk you through the process of updating your relayer account to a new one, derived from either:

* a plaintext private key, or
* an AWS KMS key.

Note that migration steps may vary depending on your current relayer client version. To check your client version, run the following command:

```sh
./bifrost-relayer --version
```

Example Output:

```sh
bifrost-relayer 2.1.1-1b4f8ca012b
```

## 1. For Relayer Client versions below v2.1.1

### 1.1. Binary Update

To update your relayer account, follow the steps below to update your relayer client to the latest version:

**Step 1.**

Remove or create a backup of the previous `bifrost-relayer` binary file before proceeding.

```sh
rm <PATH_TO_BIFROST_RELAYER_BINARY>
```

**Step 2.**

Install the latest version of `bifrost-relayer` in the same directory and update the necessary permissions. *(Note: If the directory has changed, be sure to update the Systemd configuration file accordingly)*

```sh
wget "https://github.com/bifrost-platform/bifrost-relayer.rs/releases/latest/download/bifrost-relayer"
chmod +x bifrost-relayer
```

### 1.2. Configuration Update

Before proceeding with the update, you have to first stop the running relayer. To do so, run the following command:

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl stop bifrost-relayer.service
```

The method for specifying and configuring the signer has changed. Previously, it was configured as follows:

```yaml
system:
  private_key: "0xxxx...xxx"
```

However, the configuration has now changed. The private key from the system section has been removed. Instead, you must explicitly specify a `signer_config`, which can contain either:

* A plaintext private key
* An AWS KMS key
* ⚠️ **Important:** At this step, you **must enter your previously used private key** to proceed update.

Below is the updated configuration format:

```yaml
system:
  # -----> ❌ Private key removed from here

signer_config:
  - private_key: "0xxxx...xxx"
  # -----> ⚠️ Important: Enter your previously used private key
```

Now you have two options to update your relayer account:

* **A new account derived by a plaintext private key**
  * Whenever the relayer needs to sign a message or transaction, it will use this key for signing.
* **A new account derived by an AWS KMS key**
  * Whenever the relayer needs to sign a message or transaction, it will **delegate the signing request** to the configured AWS KMS, ensuring secure and hardware-backed key management.
  * 🚨 **We highly recommend using a AWS KMS for better security.**

Choose the option that best fits your security requirements and follow the corresponding steps.

#### 1.2.1. Option 1: Private Key Derivation

To update your relayer account to a new account derived from a private key, simply add the new key to the `signer_config` section in your config.yaml file.

* ⚠️ **Important:** At this step, you **must retain your previously used private key** to proceed update.

```yaml
signer_config:
  - private_key: "0xxxx...xxx"  # -----> Retain your current private key
  - private_key: "0xxxx...xxx"  # -----> Enter your new private key
```

Now it’s fully set to go. You can now restart your relayer.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl restart bifrost-relayer.service
```

Once it successfully restarts, follow [**section #3**](#id-3.-request-account-update) to request an account update.

#### 1.2.2. Option 1: AWS KMS Key Derivation

To update your relayer account to a new account derived from an AWS KMS key, simply add the new key ID to the `signer_config` section in your config.yaml file.

* ⚠️ **Important:** At this step, you **must retain your previously used private key** to proceed update.

```yaml
signer_config:
  - private_key: "0xxxx...xxx"  # -----> Retain your current private key
  - kms_key_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"  # -----> Enter your new AWS KMS key ID
```

Now it’s fully set to go. You can now restart your relayer.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl restart bifrost-relayer.service
```

Once it successfully restarts, follow [**section #3**](#id-3.-request-account-update) to request an account update.

## 2. For Relayer Client versions higher than or equal to v2.1.1

### 2.1. Binary Update

To update your relayer account, follow the steps below to update your relayer client to the latest version:

**Step 1.**

Remove or create a backup of the previous `bifrost-relayer` binary file before proceeding.

```sh
rm <PATH_TO_BIFROST_RELAYER_BINARY>
```

**Step 2.**

Install the latest version of `bifrost-relayer` in the same directory and update the necessary permissions. *(Note: If the directory has changed, be sure to update the Systemd configuration file accordingly)*

```sh
wget "https://github.com/bifrost-platform/bifrost-relayer.rs/releases/latest/download/bifrost-relayer"
chmod +x bifrost-relayer
```

### 2.2. Configuration Update

Now you have two options to update your relayer account:

* **A new account derived by a plaintext private key**
  * Whenever the relayer needs to sign a message or transaction, it will use this key for signing.
* **A new account derived by an AWS KMS key**
  * Whenever the relayer needs to sign a message or transaction, it will **delegate the signing request** to the configured AWS KMS, ensuring secure and hardware-backed key management.
  * 🚨 **We highly recommend using a AWS KMS for better security.**

Choose the option that best fits your security requirements and follow the corresponding steps.

#### 2.2.1. Option 1: Private Key Derivation

To update your relayer account to a new account derived from a private key, simply add the new key to the `signer_config` section in your config.yaml file.

* ⚠️ **Important:** At this step, you **must retain your previously used private key** **or AWS KMS key ID** to proceed update.

```yaml
signer_config:
  - private_key: "0xxxx...xxx"  # -----> Retain your current private key or AWS KMS key ID
  - private_key: "0xxxx...xxx"  # -----> Enter your new private key
```

Now it’s fully set to go. You can now restart your relayer.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl restart bifrost-relayer.service
```

Once it successfully restarts, follow [**section #3**](#id-3.-request-account-update) to request an account update.

#### 2.2.2. Option 1: AWS KMS Key Derivation

To update your relayer account to a new account derived from an AWS KMS key, simply add the new key ID to the `signer_config` section in your config.yaml file.

* ⚠️ **Important:** At this step, you **must retain your previously used private key** **or AWS KMS key ID** to proceed update.

```yaml
signer_config:
  - private_key: "0xxxx...xxx"  # -----> Retain your current private key
  - kms_key_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"  # -----> Enter your new AWS KMS key ID
```

Now it’s fully set to go. You can now restart your relayer.

```sh
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
systemctl restart bifrost-relayer.service
```

Once it successfully restarts, follow [**section #3**](#id-3.-request-account-update) to request an account update.

## 3. Request Account Update

### 3.1. Prerequisites

Now you have to request an account update to the Bifrost network. To do so, you can simply send an extrinsic through the polkadot.js app page.

| **Mainnet**                                                                                                 | **Testnet**                                                                                                 |
| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| [link.](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpublic-02.mainnet.bifrostnetwork.com%2Fwss#/explorer) | [link.](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpublic-02.testnet.bifrostnetwork.com%2Fwss#/explorer) |

When you enter the page, you have to first register your validator’s Controller account to the page. Please follow this [**guide**](https://docs.bifrostnetwork.com/bifrost-network/running-a-node/validator-account-management#polkadot.js-account-setup) to setup your Controller account.

Before proceeding, make sure your new relayer account is properly set up and has **sufficient funds** to perform cross-chain actions.

⚠️ **Note:** You do not need to transfer the entire balance from your current account, as it still requires funds for ongoing operations.

### 3.2. Send Extrinsic: `setRelayer()`

Now to send a request to update your relayer account, proceed with the following steps in order.

1. First, access the polkadot.js web page and move on to the extrinsics tab. In prior, your controller account must be registered to polkadot.js
2. Select your own controller account.
3. Select the relayManager pallet.
4. Select the `setRelayer()` extrinsic.
5. Set the new parameter to your new account.
6. Click on the "Submit Transaction" button and send the transaction by entering your password and signing.

Once the extrinsic has been successfully executed and included in a block, the account replacement will take effect in the **next staking round**. You can simply check the remaining staking round time in our [**explorer page**](https://explorer.mainnet.bifrostnetwork.com/validators).

### 3.3. After Staking Round Update

Once the current staking round ends, your relayer account will be successfully replaced.

To confirm that the update was successful:

1. Go to our explorer page.
2. Check if your new account is actively sending transactions.

When the update is confirmed, you can remove your previous private key or AWS KMS key ID from your config.yaml file. This ensures that only the new relayer account is used for signing transactions.

⚠️ **Note**: You can now transfer the entire balance from your previous account to your new account, as it will no longer perform any operations.


# Guide for Operators


# Setting up an Endpoint Node


# Using Docker

## Introduction

The endpoint node is a node that provides a JSON-RPC interface for interacting with the Bifrost Network. Through the provided RPC methods, users or many projects can easily interact with the blockchain data. In addition to the Ethereum standard RPC interface, Geth's debug and txpool APIs and OpenEthereum's trace APIs are also selectively enabled, providing a non-standard RPC interface for bringing more detailed information about transaction processing.

The endpoint node consists of two modes. The first mode is the archive mode which stores status information on all blocks from the genesis block to the present. This mode can be used when you need to request historical data. The second mode is the non-archive mode which, unlike the archive mode, stores chain information only by the specified number of blocks. Therefore, it is not possible to request chain information outside of the set range.

As endpoint nodes do not participate in the consensus algorithm, there is no need to deposit BFC's and separate account settings, and unlike validator nodes do not lead to any special rewards.

## Install Requirements

First, create a local directory to store the chain data of the Bifrost Network. This directory stores all block information collected from the genesis block to the present.

<pre class="language-shell"><code class="lang-shell"># Add sudo at the beginning if it doesn't work
<strong>mkdir -p /var/lib/bifrost-data
</strong></code></pre>

You must set the ownership and permissions for the directory you created. If you wish to set it to a specific user, you can run the command written in “case 1” and change `DOCKER_USER` to the actual user name to run Docker later. If you wish to set it as the currently connected user, you can run the command written in "case 2".

```shell
# case 1. chown to a specific user
chown DOCKER_USER /var/lib/bifrost-data

# case 2. chown to current user
sudo chown -R $(id -u):$(id -g) /var/lib/bifrost-data
```

## Generate Peer Key

{% hint style="info" %}
This section is only required for node client versions that are higher than or equal to `v2.0.1`
{% endhint %}

Every node running on the Bifrost Network requires a peer key to connect to the P2P network. To generate a new peer key and insert it into your chain data automatically, simply run the following command.

{% tabs %}
{% tab title="Testnet" %}

```bash
docker run --rm -it -v "/var/lib/bifrost-data:/data" thebifrost/bifrost-node:latest \
    key generate-node-key \
    --chain /specs/bifrost-testnet.json \
    --base-path /data
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
docker run --rm -it -v "/var/lib/bifrost-data:/data" thebifrost/bifrost-node:latest \
    key generate-node-key \
    --chain /specs/bifrost-mainnet.json \
    --base-path /data
```

{% endtab %}
{% endtabs %}

## Run the Node Container

To run an endpoint node with the archive mode enabled, you can run the following command.

{% tabs %}
{% tab title="Testnet" %}

```bash
docker run -d -p 30333:30333 -p 9933:9933 -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-testnet.json \
  --port 30333 \
  --rpc-port 9933 \
  --state-pruning archive \
  --rpc-cors all \
  --rpc-external \
  --ethapi debug,trace,txpool \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
docker run -d -p 30333:30333 -p 9933:9933 -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-mainnet.json \
  --port 30333 \
  --rpc-port 9933 \
  --state-pruning archive \
  --rpc-cors all \
  --rpc-external \
  --ethapi debug,trace,txpool \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}
{% endtabs %}

Conversely, to run an endpoint node with the non-archive mode enabled, you can run the following command. In this case, it is necessary to determine the maximum number of past blocks to be indexed, and the number of blocks may be specified after the `--state-pruning` option.

{% tabs %}
{% tab title="Testnet" %}

```bash
docker run -d -p 30333:30333 -p 9933:9933 -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-testnet.json \
  --port 30333 \
  --rpc-port 9933 \
  --state-pruning 256 \
  --rpc-cors all \
  --rpc-external \
  --ethapi debug,trace,txpool \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
docker run -d -p 30333:30333 -p 9933:9933 -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-mainnet.json \
  --port 30333 \
  --rpc-port 9933 \
  --state-pruning 256 \
  --rpc-cors all \
  --rpc-external \
  --ethapi debug,trace,txpool \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}
{% endtabs %}

## Check Logs

To check your running `bifrost-node` container logs, execute the command below.

```sh
docker logs -f <YOUR_CONTAINER_NAME>
```

If the Docker image is successfully pulled, and the validator node is executed, the chain information will be shown as the following.

```sh
2023-07-19 17:02:53 BIFROST Network
2023-07-19 17:02:53 ✌️  version 1.2.3-0d1811a5e80
2023-07-19 17:02:53 ❤️  by bifrost-platform, 2022-2023
2023-07-19 17:02:53 📋 Chain specification: BIFROST Development
2023-07-19 17:02:53 🏷  Node name: jolly-grandfather-7771
2023-07-19 17:02:53 👤 Role: AUTHORITY
2023-07-19 17:02:53 💾 Database: RocksDb at /var/folders/vg/xzyl_nmd77x5kcvbryssc5gm0000gn/T/substrateutNaBp/chains/dev/db/full
2023-07-19 17:02:53 ⛓  Native runtime: thebifrost-dev-301 (bifrost-dev-1.tx1.au1)
2023-07-19 17:02:53 🔨 Initializing Genesis block/state (state: 0x7c59…74e5, header-hash: 0x469c…993b)
2023-07-19 17:02:53 🔨 Running Frontier DB migration from version 1 to version 2. Please wait.
2023-07-19 17:02:53 ✔️ Successful Frontier DB migration from version 1 to version 2 (0 entries).
2023-07-19 17:02:53 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2023-07-19 17:02:54 Using default protocol ID "sup" because none is configured in the chain specs
2023-07-19 17:02:54 🏷  Local node identity is: 12D3KooWLvfoahrVYuwGjvNKyyWgkWSvBT9TofHvNGdiexgS3hRL
2023-07-19 17:02:54 💻 Operating system: macos
2023-07-19 17:02:54 💻 CPU architecture: aarch64
2023-07-19 17:02:54 📦 Highest known block at #0
2023-07-19 17:02:54 〽️ Prometheus exporter started at 127.0.0.1:9615
2023-07-19 17:02:54 Running JSON-RPC HTTP server: addr=127.0.0.1:9933, allowed origins=["*"]
2023-07-19 17:02:54 Running JSON-RPC WS server: addr=127.0.0.1:9944, allowed origins=["*"]
```

Since chain data needs to be synced starting from the genesis block, the information that it is currently syncing will be shown as the following output. You can proceed to the next steps only when the sync is complete, and it may take up to several days at most.

{% hint style="info" %}
To quickly synchronize your chain data, follow this [link](/bifrost-network/running-a-node/guide-for-operators/chain-data-snapshots).
{% endhint %}

```sh
2023-07-19 17:06:20 ⚙️  Syncing, target=#8037656 (2 peers), best: #4371 (0xd39a…4f76), finalized #4200 (0x79ee…2eec), ⬇ 485.5kiB/s ⬆ 38.0kiB/s
2023-07-19 17:06:25 ⚙️  Syncing 745.8 bps, target=#8037658 (3 peers), best: #8100 (0xac9e…cba6), finalized #7800 (0xb93d…839f), ⬇ 334.1kiB/s ⬆ 24.0kiB/s
2023-07-19 17:06:30 ⚙️  Syncing 676.0 bps, target=#8037660 (3 peers), best: #11480 (0xbdbf…85f2), finalized #11400 (0x612b…7853), ⬇ 409.8kiB/s ⬆ 23.4kiB/s
2023-07-19 17:06:35 ⚙️  Syncing 596.8 bps, target=#8037661 (3 peers), best: #14465 (0xcce8…aadb), finalized #14400 (0x8f77…7e6b), ⬇ 356.1kiB/s ⬆ 24.5kiB/s
2023-07-19 17:06:40 ⚙️  Syncing 646.8 bps, target=#8037663 (3 peers), best: #17700 (0xf0a1…36d6), finalized #17408 (0x467b…63bf), ⬇ 372.7kiB/s ⬆ 9.2kiB/s
2023-07-19 17:06:45 ⚙️  Syncing 596.4 bps, target=#8037665 (3 peers), best: #20682 (0xcc4c…2ca9), finalized #20480 (0x1d99…7288), ⬇ 340.3kiB/s ⬆ 12.3kiB/s
2023-07-19 17:06:50 ⚙️  Syncing 560.2 bps, target=#8037666 (3 peers), best: #23485 (0x83ba…6fae), finalized #23400 (0xa031…a7e0), ⬇ 399.4kiB/s ⬆ 9.9kiB/s
2023-07-19 17:06:55 ⚙️  Syncing 575.0 bps, target=#8037668 (3 peers), best: #26362 (0xb11c…7fc4), finalized #26112 (0xbaa5…6c61), ⬇ 328.7kiB/s ⬆ 12.8kiB/s
2023-07-19 17:07:00 ⚙️  Syncing 579.4 bps, target=#8037670 (3 peers), best: #29259 (0xa287…cf05), finalized #29184 (0x7ac8…55cb), ⬇ 353.6kiB/s ⬆ 7.8kiB/s
2023-07-19 17:07:05 ⚙️  Syncing 595.4 bps, target=#8037671 (3 peers), best: #32237 (0xfc62…6b12), finalized #32100 (0x95cd…0c27), ⬇ 338.3kiB/s ⬆ 14.9kiB/s
2023-07-19 17:07:10 ⚙️  Syncing 590.2 bps, target=#8037673 (3 peers), best: #35191 (0x3b06…9e27), finalized #35100 (0xd461…5ab7), ⬇ 330.9kiB/s ⬆ 8.7kiB/s
```

When all the chain data sync is complete, newly generated blocks are synchronized one by one at every block time as follows.

```sh
2023-07-19 08:08:09 ✨ Imported #5384451 (0xd7a8…011f)    
2023-07-19 08:08:10 💤 Idle (25 peers), best: #5384451 (0xd7a8…011f), finalized #5384449 (0x1ae1…fdf3), ⬇ 47.7kiB/s ⬆ 49.5kiB/s    
2023-07-19 08:08:12 ✨ Imported #5384452 (0x9bf4…9710)    
2023-07-19 08:08:15 ✨ Imported #5384453 (0x90af…653a)    
2023-07-19 08:08:15 💤 Idle (25 peers), best: #5384453 (0x90af…653a), finalized #5384450 (0x8026…f68a), ⬇ 37.3kiB/s ⬆ 36.9kiB/s    
2023-07-19 08:08:18 ✨ Imported #5384454 (0x5c80…9b84)    
2023-07-19 08:08:20 💤 Idle (25 peers), best: #5384454 (0x5c80…9b84), finalized #5384452 (0x9bf4…9710), ⬇ 38.0kiB/s ⬆ 46.4kiB/s    
2023-07-19 08:08:21 ✨ Imported #5384455 (0x91d0…de42)    
2023-07-19 08:08:24 ✨ Imported #5384456 (0xb7e0…832e)    
2023-07-19 08:08:25 💤 Idle (25 peers), best: #5384456 (0xb7e0…832e), finalized #5384454 (0x5c80…9b84), ⬇ 46.2kiB/s ⬆ 44.2kiB/s    
2023-07-19 08:08:27 ✨ Imported #5384457 (0xcc84…0e00)    
2023-07-19 08:08:30 ✨ Imported #5384458 (0xc499…2475)    
2023-07-19 08:08:30 💤 Idle (25 peers), best: #5384458 (0xc499…2475), finalized #5384455 (0x91d0…de42), ⬇ 28.5kiB/s ⬆ 44.0kiB/s    
```

## Update Node Client

As Bifrost Network development continues, it will sometimes be necessary to upgrade your node client. Node operators will be notified on our Discord channel or by personal contacts when upgrades are available and whether they are necessary (some client upgrades are optional).&#x20;

Before upgrading your node client, please keep a backup file of your chain data to prevent any further data, keys, or credential losses.

{% tabs %}
{% tab title="Testnet" %}

```bash
# First of all stop bifrost-node
docker stop "YOUR_CONTAINER_NAME"
docker rm "YOUR_CONTAINER_NAME"

# Pull the latest bifrost-node image
docker pull thebifrost/bifrost-node:latest

# Change bifrost-node image version(tag) on run command
# e.g.
docker run -d -p 30333:30333 -p 9933:9933 -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-testnet.json \
  --port 30333 \
  --rpc-port 9933 \
  --state-pruning archive \
  --rpc-cors all \
  --rpc-external \
  --ethapi debug,trace,txpool \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
# First of all stop bifrost-node
docker stop "YOUR_CONTAINER_NAME"
docker rm "YOUR_CONTAINER_NAME"

# Pull the latest bifrost-node image
docker pull thebifrost/bifrost-node:latest

# Change bifrost-node image version(tag) on run command
# e.g.
docker run -d -p 30333:30333 -p 9933:9933 -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-mainnet.json \
  --port 30333 \
  --rpc-port 9933 \
  --state-pruning archive \
  --rpc-cors all \
  --rpc-external \
  --ethapi debug,trace,txpool \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}
{% endtabs %}


# Using Systemd

## Install Requirements

In addition to using the Docker image, there are ways to run nodes with the Linux system daemon as a Systemd service. The service will work on most Linux operating systems. However, Debian/Ubuntu is the only environment in which all tests have been completed, and the manual has been written based on this environment.

First, create a service account to run the node service.

```bash
adduser BIFROST_SERVICE --system --no-create-home
```

Next, create a local directory to store the chain data of the Bifrost Network. This directory contains the node binary and block information collected from the genesis block to the present.

```bash
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
mkdir -p /var/lib/bifrost-data
```

Then, download the latest node execution binary and chain specification JSON file from our Github releases. You can check the latest releases by going to our GitHub repository under the [releases](https://github.com/bifrost-platform/bifrost-node/releases) page.

{% tabs %}
{% tab title="Testnet" %}

```bash
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-testnet.json"
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-mainnet.json"
```

{% endtab %}
{% endtabs %}

At last, grant an execution permission to the node binary and move it to your chain data directory.

{% tabs %}
{% tab title="Testnet" %}

```bash
chmod +x bifrost-node
mv bifrost-node bifrost-testnet.json /var/lib/bifrost-data
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
chmod +x bifrost-node
mv bifrost-node bifrost-mainnet.json /var/lib/bifrost-data
```

{% endtab %}
{% endtabs %}

## Generate Peer Key

{% hint style="info" %}
This section is only required for node client versions that are higher than or equal to `v2.0.1`
{% endhint %}

Every node running on the Bifrost Network requires a peer key to connect to the P2P network. To generate a new peer key and insert it into your chain data automatically, simply run the following command.

{% tabs %}
{% tab title="Testnet" %}

```bash
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
/var/lib/bifrost-data/bifrost-node key generate-node-key \
    --chain /var/lib/bifrost-data/bifrost-testnet.json \
    --base-path /var/lib/bifrost-data
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
/var/lib/bifrost-data/bifrost-node key generate-node-key \
    --chain /var/lib/bifrost-data/bifrost-mainnet.json \
    --base-path /var/lib/bifrost-data
```

{% endtab %}
{% endtabs %}

## Run the Node Service

First, set ownership permission to your chain data directory to the service account.

```bash
chown -R BIFROST_SERVICE /var/lib/bifrost-data
```

Next, you need to create a Systemd configuration file. In the example below, change `YOUR_NODE_NAME` to the desired name of your node service, and save the file in the following directory.

```sh
sudo vi /etc/systemd/system/bifrost-node.service
```

{% tabs %}
{% tab title="Testnet" %}

```systemd
[Unit]
Description="Bifrost-node systemd service"
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=BIFROST_SERVICE
SyslogIdentifier=bifrost-node
SyslogFacility=local7
KillSignal=SIGHUP
ExecStart=/var/lib/bifrost-data/bifrost-node \
    --base-path /var/lib/bifrost-data \
    --chain /var/lib/bifrost-data/bifrost-testnet.json \
    --port 30333 \
    --rpc-port 9933 \
    --state-pruning archive \
    --rpc-cors all \
    --rpc-external \
    --ethapi debug,trace,txpool \
    --runtime-cache-size 64 \
    --name "YOUR_NODE_NAME"

[Install]
WantedBy=multi-user.target
```

{% endtab %}

{% tab title="Mainnet" %}

```systemd
[Unit]
Description="Bifrost-node systemd service"
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=BIFROST_SERVICE
SyslogIdentifier=bifrost-node
SyslogFacility=local7
KillSignal=SIGHUP
ExecStart=/var/lib/bifrost-data/bifrost-node \
    --base-path /var/lib/bifrost-data \
    --chain /var/lib/bifrost-data/bifrost-mainnet.json \
    --port 30333 \
    --rpc-port 9933 \
    --state-pruning archive \
    --rpc-cors all \
    --rpc-external \
    --ethapi debug,trace,txpool \
    --runtime-cache-size 64 \
    --name "YOUR_NODE_NAME"

[Install]
WantedBy=multi-user.target
```

{% endtab %}
{% endtabs %}

Conversely, to run an endpoint node with non-archive mode enabled, it is necessary to determine the maximum number of past blocks to be indexed, and the number of blocks may be specified after the `--state-pruning` option.

Now, with the two lines of the command below, the node service will run in the background.

```bash
systemctl enable bifrost-node.service
systemctl start bifrost-node.service
```

## Check Logs

To check your running `bifrost-node` service logs, execute the command below.

```sh
journalctl -f -u bifrost-node
```

If the node service has successfully been executed, the chain information will be shown as the following.

```sh
2023-07-19 17:02:53 BIFROST Network
2023-07-19 17:02:53 ✌️  version 1.2.3-0d1811a5e80
2023-07-19 17:02:53 ❤️  by bifrost-platform, 2022-2023
2023-07-19 17:02:53 📋 Chain specification: BIFROST Development
2023-07-19 17:02:53 🏷  Node name: jolly-grandfather-7771
2023-07-19 17:02:53 👤 Role: AUTHORITY
2023-07-19 17:02:53 💾 Database: RocksDb at /var/folders/vg/xzyl_nmd77x5kcvbryssc5gm0000gn/T/substrateutNaBp/chains/dev/db/full
2023-07-19 17:02:53 ⛓  Native runtime: thebifrost-dev-301 (bifrost-dev-1.tx1.au1)
2023-07-19 17:02:53 🔨 Initializing Genesis block/state (state: 0x7c59…74e5, header-hash: 0x469c…993b)
2023-07-19 17:02:53 🔨 Running Frontier DB migration from version 1 to version 2. Please wait.
2023-07-19 17:02:53 ✔️ Successful Frontier DB migration from version 1 to version 2 (0 entries).
2023-07-19 17:02:53 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2023-07-19 17:02:54 Using default protocol ID "sup" because none is configured in the chain specs
2023-07-19 17:02:54 🏷  Local node identity is: 12D3KooWLvfoahrVYuwGjvNKyyWgkWSvBT9TofHvNGdiexgS3hRL
2023-07-19 17:02:54 💻 Operating system: macos
2023-07-19 17:02:54 💻 CPU architecture: aarch64
2023-07-19 17:02:54 📦 Highest known block at #0
2023-07-19 17:02:54 〽️ Prometheus exporter started at 127.0.0.1:9615
2023-07-19 17:02:54 Running JSON-RPC HTTP server: addr=127.0.0.1:9933, allowed origins=["*"]
2023-07-19 17:02:54 Running JSON-RPC WS server: addr=127.0.0.1:9944, allowed origins=["*"]
```

Since chain data needs to be synced starting from the genesis block, the information that it is currently syncing will be shown as the following output. You can proceed to the next steps only when the sync is complete, and it may take up to several days at most.

{% hint style="info" %}
To quickly synchronize your chain data, follow this [link](/bifrost-network/running-a-node/guide-for-operators/chain-data-snapshots).
{% endhint %}

```sh
2023-07-19 17:06:20 ⚙️  Syncing, target=#8037656 (2 peers), best: #4371 (0xd39a…4f76), finalized #4200 (0x79ee…2eec), ⬇ 485.5kiB/s ⬆ 38.0kiB/s
2023-07-19 17:06:25 ⚙️  Syncing 745.8 bps, target=#8037658 (3 peers), best: #8100 (0xac9e…cba6), finalized #7800 (0xb93d…839f), ⬇ 334.1kiB/s ⬆ 24.0kiB/s
2023-07-19 17:06:30 ⚙️  Syncing 676.0 bps, target=#8037660 (3 peers), best: #11480 (0xbdbf…85f2), finalized #11400 (0x612b…7853), ⬇ 409.8kiB/s ⬆ 23.4kiB/s
2023-07-19 17:06:35 ⚙️  Syncing 596.8 bps, target=#8037661 (3 peers), best: #14465 (0xcce8…aadb), finalized #14400 (0x8f77…7e6b), ⬇ 356.1kiB/s ⬆ 24.5kiB/s
2023-07-19 17:06:40 ⚙️  Syncing 646.8 bps, target=#8037663 (3 peers), best: #17700 (0xf0a1…36d6), finalized #17408 (0x467b…63bf), ⬇ 372.7kiB/s ⬆ 9.2kiB/s
2023-07-19 17:06:45 ⚙️  Syncing 596.4 bps, target=#8037665 (3 peers), best: #20682 (0xcc4c…2ca9), finalized #20480 (0x1d99…7288), ⬇ 340.3kiB/s ⬆ 12.3kiB/s
2023-07-19 17:06:50 ⚙️  Syncing 560.2 bps, target=#8037666 (3 peers), best: #23485 (0x83ba…6fae), finalized #23400 (0xa031…a7e0), ⬇ 399.4kiB/s ⬆ 9.9kiB/s
2023-07-19 17:06:55 ⚙️  Syncing 575.0 bps, target=#8037668 (3 peers), best: #26362 (0xb11c…7fc4), finalized #26112 (0xbaa5…6c61), ⬇ 328.7kiB/s ⬆ 12.8kiB/s
2023-07-19 17:07:00 ⚙️  Syncing 579.4 bps, target=#8037670 (3 peers), best: #29259 (0xa287…cf05), finalized #29184 (0x7ac8…55cb), ⬇ 353.6kiB/s ⬆ 7.8kiB/s
2023-07-19 17:07:05 ⚙️  Syncing 595.4 bps, target=#8037671 (3 peers), best: #32237 (0xfc62…6b12), finalized #32100 (0x95cd…0c27), ⬇ 338.3kiB/s ⬆ 14.9kiB/s
2023-07-19 17:07:10 ⚙️  Syncing 590.2 bps, target=#8037673 (3 peers), best: #35191 (0x3b06…9e27), finalized #35100 (0xd461…5ab7), ⬇ 330.9kiB/s ⬆ 8.7kiB/s
```

When the chain data is completely synchronized, newly generated blocks will start to synchronize one by one at every block time as follows.

```sh
2023-07-19 08:08:09 ✨ Imported #5384451 (0xd7a8…011f)    
2023-07-19 08:08:10 💤 Idle (25 peers), best: #5384451 (0xd7a8…011f), finalized #5384449 (0x1ae1…fdf3), ⬇ 47.7kiB/s ⬆ 49.5kiB/s    
2023-07-19 08:08:12 ✨ Imported #5384452 (0x9bf4…9710)    
2023-07-19 08:08:15 ✨ Imported #5384453 (0x90af…653a)    
2023-07-19 08:08:15 💤 Idle (25 peers), best: #5384453 (0x90af…653a), finalized #5384450 (0x8026…f68a), ⬇ 37.3kiB/s ⬆ 36.9kiB/s    
2023-07-19 08:08:18 ✨ Imported #5384454 (0x5c80…9b84)    
2023-07-19 08:08:20 💤 Idle (25 peers), best: #5384454 (0x5c80…9b84), finalized #5384452 (0x9bf4…9710), ⬇ 38.0kiB/s ⬆ 46.4kiB/s    
2023-07-19 08:08:21 ✨ Imported #5384455 (0x91d0…de42)    
2023-07-19 08:08:24 ✨ Imported #5384456 (0xb7e0…832e)    
2023-07-19 08:08:25 💤 Idle (25 peers), best: #5384456 (0xb7e0…832e), finalized #5384454 (0x5c80…9b84), ⬇ 46.2kiB/s ⬆ 44.2kiB/s    
2023-07-19 08:08:27 ✨ Imported #5384457 (0xcc84…0e00)    
2023-07-19 08:08:30 ✨ Imported #5384458 (0xc499…2475)    
2023-07-19 08:08:30 💤 Idle (25 peers), best: #5384458 (0xc499…2475), finalized #5384455 (0x91d0…de42), ⬇ 28.5kiB/s ⬆ 44.0kiB/s    
```

## Update Node Client

As Bifrost Network development continues, it will sometimes be necessary to upgrade your node client. Node operators will be notified on our Discord channel or by personal contacts when upgrades are available and whether they are necessary (some client upgrades are optional).&#x20;

Before upgrading your node client, please keep a backup file of your chain data to prevent any further data, keys, or credential losses.

{% tabs %}
{% tab title="Testnet" %}

```bash
# Stop and delete bifrost-node binary
systemctl stop bifrost-node.service
rm /var/lib/bifrost-data/bifrost-node
rm /var/lib/bifrost-data/bifrost-testnet.json

# Download the latest bifrost-node binary and chain specification JSON file
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-testnet.json"

# Grant execute permission & move to chain data directory
chmod +x bifrost-node
chown BIFROST_SERVICE bifrost-node
mv bifrost-node /var/lib/bifrost-data
mv bifrost-testnet.json /var/lib/bifrost-data

systemctl restart bifrost-node.service
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
# Stop and delete bifrost-node binary
systemctl stop bifrost-node.service
rm /var/lib/bifrost-data/bifrost-node
rm /var/lib/bifrost-data/bifrost-mainnet.json

# Download the latest bifrost-node binary and chain specification JSON file
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-mainnet.json"

# Grant execute permission & move to chain data directory
chmod +x bifrost-node
chown BIFROST_SERVICE bifrost-node
mv bifrost-node /var/lib/bifrost-data
mv bifrost-mainnet.json /var/lib/bifrost-data

systemctl restart bifrost-node.service
```

{% endtab %}
{% endtabs %}


# Setting up a Validator Node


# Using Docker

## Install Requirements

All types of Bifrost Network nodes can be executed easily through [Docker](https://docs.docker.com/get-docker/). Docker must be pre-installed in the environment you wish to run the node. Once installed, you can proceed with the following process.

First, create a local directory to store the chain data of the Bifrost Network. This directory stores all block information collected from the genesis block to the present and additional session keys of the corresponding validator node.

```bash
# Add sudo at the beginning if it doesn't work
mkdir -p /var/lib/bifrost-data
```

You must set the ownership and permissions for the directory you created. If you wish to set it to a specific user, you can run the command written in “case 1” and change `DOCKER_USER` to the actual user name to run Docker later. If you want to set it as the currently connected user, you can run the command written in "case 2".

```bash
# case 1. chown to a specific user
chown DOCKER_USER /var/lib/bifrost-data

# case 2. chown to current user
sudo chown -R $(id -u):$(id -g) /var/lib/bifrost-data
```

## Generate Peer Key

{% hint style="info" %}
This section is only required for node client versions that are higher than or equal to `v2.0.1`
{% endhint %}

Every node running on the Bifrost Network requires a peer key to connect to the P2P network. To generate a new peer key and insert it into your chain data automatically, simply run the following command.

{% tabs %}
{% tab title="Testnet" %}

```bash
docker run --rm -it -v "/var/lib/bifrost-data:/data" thebifrost/bifrost-node:latest \
    key generate-node-key \
    --chain /specs/bifrost-testnet.json \
    --base-path /data
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
docker run --rm -it -v "/var/lib/bifrost-data:/data" thebifrost/bifrost-node:latest \
    key generate-node-key \
    --chain /specs/bifrost-mainnet.json \
    --base-path /data
```

{% endtab %}
{% endtabs %}

## Run the Node Container

To run the validator node, you can simply run the following command. In this case, `YOUR_NODE_NAME` is a parameter indicating the name of the node to be executed and should be modified to the desired name.

{% tabs %}
{% tab title="Testnet" %}

```bash
docker run -d --network host -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-testnet.json \
  --port 30333 \
  --validator \
  --state-pruning archive \
  --trie-cache-size 0 \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
docker run -d --network host -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-mainnet.json \
  --port 30333 \
  --validator \
  --state-pruning archive \
  --trie-cache-size 0 \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}
{% endtabs %}

## Check Logs

To check your running `bifrost-node` container logs, execute the command below.

```sh
docker logs -f <YOUR_CONTAINER_NAME>
```

If the Docker image is successfully pulled, and the validator node is executed, the chain information will be shown as the following.

```sh
2023-07-19 17:02:53 BIFROST Network
2023-07-19 17:02:53 ✌️  version 1.2.3-0d1811a5e80
2023-07-19 17:02:53 ❤️  by bifrost-platform, 2022-2023
2023-07-19 17:02:53 📋 Chain specification: BIFROST Development
2023-07-19 17:02:53 🏷  Node name: jolly-grandfather-7771
2023-07-19 17:02:53 👤 Role: AUTHORITY
2023-07-19 17:02:53 💾 Database: RocksDb at /var/folders/vg/xzyl_nmd77x5kcvbryssc5gm0000gn/T/substrateutNaBp/chains/dev/db/full
2023-07-19 17:02:53 ⛓  Native runtime: thebifrost-dev-301 (bifrost-dev-1.tx1.au1)
2023-07-19 17:02:53 🔨 Initializing Genesis block/state (state: 0x7c59…74e5, header-hash: 0x469c…993b)
2023-07-19 17:02:53 🔨 Running Frontier DB migration from version 1 to version 2. Please wait.
2023-07-19 17:02:53 ✔️ Successful Frontier DB migration from version 1 to version 2 (0 entries).
2023-07-19 17:02:53 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2023-07-19 17:02:54 Using default protocol ID "sup" because none is configured in the chain specs
2023-07-19 17:02:54 🏷  Local node identity is: 12D3KooWLvfoahrVYuwGjvNKyyWgkWSvBT9TofHvNGdiexgS3hRL
2023-07-19 17:02:54 💻 Operating system: macos
2023-07-19 17:02:54 💻 CPU architecture: aarch64
2023-07-19 17:02:54 📦 Highest known block at #0
2023-07-19 17:02:54 〽️ Prometheus exporter started at 127.0.0.1:9615
2023-07-19 17:02:54 Running JSON-RPC HTTP server: addr=127.0.0.1:9933, allowed origins=["*"]
2023-07-19 17:02:54 Running JSON-RPC WS server: addr=127.0.0.1:9944, allowed origins=["*"]
```

Since chain data needs to be synced starting from the genesis block, the information that it is currently syncing will be shown as the following output. You can proceed to the next steps only when the sync is complete, and it may take up to several days at most.

{% hint style="info" %}
To quickly synchronize your chain data, follow this [link](/bifrost-network/running-a-node/guide-for-operators/chain-data-snapshots).
{% endhint %}

```sh
2023-07-19 17:06:20 ⚙️  Syncing, target=#8037656 (2 peers), best: #4371 (0xd39a…4f76), finalized #4200 (0x79ee…2eec), ⬇ 485.5kiB/s ⬆ 38.0kiB/s
2023-07-19 17:06:25 ⚙️  Syncing 745.8 bps, target=#8037658 (3 peers), best: #8100 (0xac9e…cba6), finalized #7800 (0xb93d…839f), ⬇ 334.1kiB/s ⬆ 24.0kiB/s
2023-07-19 17:06:30 ⚙️  Syncing 676.0 bps, target=#8037660 (3 peers), best: #11480 (0xbdbf…85f2), finalized #11400 (0x612b…7853), ⬇ 409.8kiB/s ⬆ 23.4kiB/s
2023-07-19 17:06:35 ⚙️  Syncing 596.8 bps, target=#8037661 (3 peers), best: #14465 (0xcce8…aadb), finalized #14400 (0x8f77…7e6b), ⬇ 356.1kiB/s ⬆ 24.5kiB/s
2023-07-19 17:06:40 ⚙️  Syncing 646.8 bps, target=#8037663 (3 peers), best: #17700 (0xf0a1…36d6), finalized #17408 (0x467b…63bf), ⬇ 372.7kiB/s ⬆ 9.2kiB/s
2023-07-19 17:06:45 ⚙️  Syncing 596.4 bps, target=#8037665 (3 peers), best: #20682 (0xcc4c…2ca9), finalized #20480 (0x1d99…7288), ⬇ 340.3kiB/s ⬆ 12.3kiB/s
2023-07-19 17:06:50 ⚙️  Syncing 560.2 bps, target=#8037666 (3 peers), best: #23485 (0x83ba…6fae), finalized #23400 (0xa031…a7e0), ⬇ 399.4kiB/s ⬆ 9.9kiB/s
2023-07-19 17:06:55 ⚙️  Syncing 575.0 bps, target=#8037668 (3 peers), best: #26362 (0xb11c…7fc4), finalized #26112 (0xbaa5…6c61), ⬇ 328.7kiB/s ⬆ 12.8kiB/s
2023-07-19 17:07:00 ⚙️  Syncing 579.4 bps, target=#8037670 (3 peers), best: #29259 (0xa287…cf05), finalized #29184 (0x7ac8…55cb), ⬇ 353.6kiB/s ⬆ 7.8kiB/s
2023-07-19 17:07:05 ⚙️  Syncing 595.4 bps, target=#8037671 (3 peers), best: #32237 (0xfc62…6b12), finalized #32100 (0x95cd…0c27), ⬇ 338.3kiB/s ⬆ 14.9kiB/s
2023-07-19 17:07:10 ⚙️  Syncing 590.2 bps, target=#8037673 (3 peers), best: #35191 (0x3b06…9e27), finalized #35100 (0xd461…5ab7), ⬇ 330.9kiB/s ⬆ 8.7kiB/s
```

When the chain data is completely synchronized, newly generated blocks will start to synchronize one by one at every block time as follows.

```sh
2023-07-19 08:08:09 ✨ Imported #5384451 (0xd7a8…011f)    
2023-07-19 08:08:10 💤 Idle (25 peers), best: #5384451 (0xd7a8…011f), finalized #5384449 (0x1ae1…fdf3), ⬇ 47.7kiB/s ⬆ 49.5kiB/s    
2023-07-19 08:08:12 ✨ Imported #5384452 (0x9bf4…9710)    
2023-07-19 08:08:15 ✨ Imported #5384453 (0x90af…653a)    
2023-07-19 08:08:15 💤 Idle (25 peers), best: #5384453 (0x90af…653a), finalized #5384450 (0x8026…f68a), ⬇ 37.3kiB/s ⬆ 36.9kiB/s    
2023-07-19 08:08:18 ✨ Imported #5384454 (0x5c80…9b84)    
2023-07-19 08:08:20 💤 Idle (25 peers), best: #5384454 (0x5c80…9b84), finalized #5384452 (0x9bf4…9710), ⬇ 38.0kiB/s ⬆ 46.4kiB/s    
2023-07-19 08:08:21 ✨ Imported #5384455 (0x91d0…de42)    
2023-07-19 08:08:24 ✨ Imported #5384456 (0xb7e0…832e)    
2023-07-19 08:08:25 💤 Idle (25 peers), best: #5384456 (0xb7e0…832e), finalized #5384454 (0x5c80…9b84), ⬇ 46.2kiB/s ⬆ 44.2kiB/s    
2023-07-19 08:08:27 ✨ Imported #5384457 (0xcc84…0e00)    
2023-07-19 08:08:30 ✨ Imported #5384458 (0xc499…2475)    
2023-07-19 08:08:30 💤 Idle (25 peers), best: #5384458 (0xc499…2475), finalized #5384455 (0x91d0…de42), ⬇ 28.5kiB/s ⬆ 44.0kiB/s    
```

## Key Setup and Bonding

We now proceed with the key setting that is required to allow the validator node to perform the process of block generation and finalization. From this step, the chain data synchronization of the running node must be completed.

First, validator nodes essentially require two Ethereum-style accounts, the controller and stash accounts, and in the case of full nodes, an additional relayer account is required.

A stash account is an account that holds a certain amount of self-bond that must be deposited in the system so that the delegated account can act as a validator. The role of a stash account is to deposit self-bonds and delegate one account (controller) to perform validator activities publicly on its behalf.

The controller account is the delegated target from the stash account and is the prime account that acts as a validator. The role of the controller is an account that is dedicated to all activities such as session key registration, block generation, finalization, etc., and requires minimal assets to pay transaction fees.

If you need to create a new account, you can run the following commands.

```bash
# step 1. access your docker container
docker exec -it YOUR_CONTAINER_NAME /bin/bash

# step 2. move to the tools directory
cd tools

# step 3. install required packages
npm install

# step 4. generate validator accounts

# case 1. generate accounts for basic nodes
npm run create_accounts

# case 2. generate accounts for full nodes
npm run create_accounts -- --full
```

After executing the command, the available new validator accounts will be printed as follows. You must send enough BFC to each account that meets the requirements to proceed to the next process.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FYqqR5ZqstwwW6Vxd3xXx%2Fdocker4.png?alt=media&amp;token=eaa7cc58-8ed6-4a46-94cf-8f8bdce33dab" alt=""><figcaption></figcaption></figure>

Next, the validator node must issue and register session keys to be used in the consensus algorithm. The process can be performed by executing the following command. Make sure that you are in the `tools` directory.

```bash
npm run set_session_keys -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY"
```

<details>

<summary>Example</summary>

```sh
npm run set_session_keys -- \
  --controllerPrivate 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133
```

</details>

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FeXqFwkSxiSwE8vev8ZA1%2Fdocker5.png?alt=media&amp;token=8326bc1f-03e5-4a76-99d7-2e7e37182fd2" alt=""><figcaption></figcaption></figure>

This command will generate three session keys for your node. Each key has their own purpose. `Aura` is for block creation, `grandpa` is for block finalization, and `ImOnline` is for node liveness. The generated keys will be stored in your chain data directory. The directory path will look like this: `/var/lib/bifrost-data/chains/{testnet|mainnet}/keystore`.

Finally, it is necessary to deposit the self-bonds of the validator node to form the initial voting power. The process can be performed by executing the following command.

```bash
# case 1. join as a basic node
npm run join_validator_candidates -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY" \
  --stashPrivate "YOUR_STASH_PRIVATE_KEY" \
  --bond "YOUR_SELF_BOND_AMOUNT_IN_BFC"

# case 2. join as a full node
npm run join_validator_candidates -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY" \
  --stashPrivate "YOUR_STASH_PRIVATE_KEY" \
  --relayerPrivate "YOUR_RELAYER_PRIVATE_KEY" \
  --bond "YOUR_SELF_BOND_AMOUNT_IN_BFC"
```

<details>

<summary>Example</summary>

```sh
npm run join_validator_candidates -- \
  --controllerPrivate 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133 \
  --stashPrivate 0x234871e7f7520af0cfc9f8547057b283c628be93a90b393aa19be1279ee52b4a \
  --relayerPrivate 0xcc01ee486e8717dc3911ede9293b767e29ce66f5c987da45887cb61822700117 \
  --bond 1000
```

</details>

If you have successfully completed every process mentioned above, the amount of BFC deposited from the stash account will be deducted from the wallet, and your controller account will participate in the active validator update process in the next round. You can check whether or not you successfully joined the validator pool on the following [page](https://www.bifrostnetwork.com/stake).

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FZKTXm2QxcB6WAKqTJgHi%2Fdocker6.png?alt=media&amp;token=7a76072c-a1ff-4a8c-a25f-2d88bcc757fd" alt=""><figcaption></figcaption></figure>

If the tier of the validator node to be operated is a full node, it must be operated together with the relayer. The manual for relayer setup can be found in the "[Setting up a Relayer](/bifrost-network/running-a-node/guide-for-operators/setting-up-a-relayer/bifrost-relayer.rs)" section.

## Update Node Client

As Bifrost Network development continues, it will sometimes be necessary to upgrade your node client. Node operators will be notified on our Discord channel or by personal contacts when upgrades are available and whether they are necessary (some client upgrades are optional).&#x20;

Before upgrading your node client, please keep a backup file of your chain data to prevent any further data, keys, or credential losses.

{% tabs %}
{% tab title="Testnet" %}

```bash
# First of all stop bifrost-node
docker stop "YOUR_CONTAINER_NAME"
docker rm "YOUR_CONTAINER_NAME"

# Pull the latest bifrost-node image
docker pull thebifrost/bifrost-node:latest

# Change bifrost-node version on run command
# e.g.
docker run -d --network host -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-testnet.json \
  --port 30333 \
  --validator \
  --state-pruning archive \
  --trie-cache-size 0 \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
# First of all stop bifrost-node
docker stop "YOUR_CONTAINER_NAME"
docker rm "YOUR_CONTAINER_NAME"

# Pull the latest bifrost-node image
docker pull thebifrost/bifrost-node:latest

# Change bifrost-node version on run command
# e.g.
docker run -d --network host -v "/var/lib/bifrost-data:/data" --name "YOUR_CONTAINER_NAME" thebifrost/bifrost-node:latest \
  --base-path /data \
  --chain /specs/bifrost-mainnet.json \
  --port 30333 \
  --validator \
  --state-pruning archive \
  --trie-cache-size 0 \
  --runtime-cache-size 64 \
  --name "YOUR_NODE_NAME"
```

{% endtab %}
{% endtabs %}


# Using Systemd

## Install Requirements

In addition to using the Docker image, there are ways to run nodes with the Linux system daemon as a Systemd service. The service will work on most Linux operating systems. However, Debian/Ubuntu is the only environment in which all tests have been completed, and the manual has been written based on this environment.

First, create a service account to run the node service.

```bash
adduser BIFROST_SERVICE --system --no-create-home
```

Next, create a local directory to store the chain data of the Bifrost Network. This directory will contain the node binary and all block information collected from the genesis block to the present and additional session keys of the corresponding validator node.

```bash
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
mkdir -p /var/lib/bifrost-data
```

Then, download the latest node execution binary and chain specification JSON file from our Github releases. You can check the latest releases by going to our GitHub repository under the [releases](https://github.com/bifrost-platform/bifrost-node/releases) page.

{% tabs %}
{% tab title="Testnet" %}

```bash
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-testnet.json"
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-mainnet.json"
```

{% endtab %}
{% endtabs %}

At last, grant an execution permission to the node binary and move it to your chain data directory.

{% tabs %}
{% tab title="Testnet" %}

```bash
chmod +x bifrost-node
mv bifrost-node bifrost-testnet.json /var/lib/bifrost-data
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
chmod +x bifrost-node
mv bifrost-node bifrost-mainnet.json /var/lib/bifrost-data
```

{% endtab %}
{% endtabs %}

## Generate Peer Key

{% hint style="info" %}
This section is only required for node client versions that are higher than or equal to `v2.0.1`
{% endhint %}

Every node running on the Bifrost Network requires a peer key to connect to the P2P network. To generate a new peer key and insert it into your chain data automatically, simply run the following command.

{% tabs %}
{% tab title="Testnet" %}

```bash
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
/var/lib/bifrost-data/bifrost-node key generate-node-key \
    --chain /var/lib/bifrost-data/bifrost-testnet.json \
    --base-path /var/lib/bifrost-data
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
# Add sudo at the beginning if it doesn't work (i.e. Permission Denied)
/var/lib/bifrost-data/bifrost-node key generate-node-key \
    --chain /var/lib/bifrost-data/bifrost-mainnet.json \
    --base-path /var/lib/bifrost-data
```

{% endtab %}
{% endtabs %}

## Run the Node Service

First, set ownership permission to your chain data directory to the service account.

```bash
chown -R BIFROST_SERVICE /var/lib/bifrost-data
```

Next, you need to create a Systemd configuration file. In the example below, change `YOUR_NODE_NAME` to the desired name of your node service, and save the file in the following directory.

```sh
sudo vi /etc/systemd/system/bifrost-node.service
```

{% tabs %}
{% tab title="Testnet" %}

```systemd
[Unit]
Description="Bifrost-node systemd service"
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=BIFROST_SERVICE
SyslogIdentifier=bifrost-node
SyslogFacility=local7
KillSignal=SIGHUP
ExecStart=/var/lib/bifrost-data/bifrost-node \
    --base-path /var/lib/bifrost-data \
    --chain /var/lib/bifrost-data/bifrost-testnet.json \
    --port 30333 \
    --validator \
    --state-pruning archive \
    --trie-cache-size 0 \
    --runtime-cache-size 64 \
    --name "YOUR_NODE_NAME"

[Install]
WantedBy=multi-user.target
```

{% endtab %}

{% tab title="Mainnet" %}

```systemd
[Unit]
Description="Bifrost-node systemd service"
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
User=BIFROST_SERVICE
SyslogIdentifier=bifrost-node
SyslogFacility=local7
KillSignal=SIGHUP
ExecStart=/var/lib/bifrost-data/bifrost-node \
    --base-path /var/lib/bifrost-data \
    --chain /var/lib/bifrost-data/bifrost-mainnet.json \
    --port 30333 \
    --validator \
    --state-pruning archive \
    --trie-cache-size 0 \
    --runtime-cache-size 64 \
    --name "YOUR_NODE_NAME"

[Install]
WantedBy=multi-user.target
```

{% endtab %}
{% endtabs %}

Now, with the two lines of the command below, the node service will run in the background.

```bash
systemctl enable bifrost-node.service
systemctl start bifrost-node.service
```

## Check Logs

To check your running `bifrost-node` service logs, execute the command below.

```sh
journalctl -f -u bifrost-node
```

If the node service has successfully been executed, the chain information will be shown as the following.

```sh
2023-07-19 17:02:53 BIFROST Network
2023-07-19 17:02:53 ✌️  version 1.2.3-0d1811a5e80
2023-07-19 17:02:53 ❤️  by bifrost-platform, 2022-2023
2023-07-19 17:02:53 📋 Chain specification: BIFROST Development
2023-07-19 17:02:53 🏷  Node name: jolly-grandfather-7771
2023-07-19 17:02:53 👤 Role: AUTHORITY
2023-07-19 17:02:53 💾 Database: RocksDb at /var/folders/vg/xzyl_nmd77x5kcvbryssc5gm0000gn/T/substrateutNaBp/chains/dev/db/full
2023-07-19 17:02:53 ⛓  Native runtime: thebifrost-dev-301 (bifrost-dev-1.tx1.au1)
2023-07-19 17:02:53 🔨 Initializing Genesis block/state (state: 0x7c59…74e5, header-hash: 0x469c…993b)
2023-07-19 17:02:53 🔨 Running Frontier DB migration from version 1 to version 2. Please wait.
2023-07-19 17:02:53 ✔️ Successful Frontier DB migration from version 1 to version 2 (0 entries).
2023-07-19 17:02:53 👴 Loading GRANDPA authority set from genesis on what appears to be first startup.
2023-07-19 17:02:54 Using default protocol ID "sup" because none is configured in the chain specs
2023-07-19 17:02:54 🏷  Local node identity is: 12D3KooWLvfoahrVYuwGjvNKyyWgkWSvBT9TofHvNGdiexgS3hRL
2023-07-19 17:02:54 💻 Operating system: macos
2023-07-19 17:02:54 💻 CPU architecture: aarch64
2023-07-19 17:02:54 📦 Highest known block at #0
2023-07-19 17:02:54 〽️ Prometheus exporter started at 127.0.0.1:9615
2023-07-19 17:02:54 Running JSON-RPC HTTP server: addr=127.0.0.1:9933, allowed origins=["*"]
2023-07-19 17:02:54 Running JSON-RPC WS server: addr=127.0.0.1:9944, allowed origins=["*"]
```

Since chain data needs to be synced starting from the genesis block, the information that it is currently syncing will be shown as the following output. You can proceed to the next steps only when the sync is complete, and it may take up to several days at most.

{% hint style="info" %}
To quickly synchronize your chain data, follow this [link](/bifrost-network/running-a-node/guide-for-operators/chain-data-snapshots).
{% endhint %}

```sh
2023-07-19 17:06:20 ⚙️  Syncing, target=#8037656 (2 peers), best: #4371 (0xd39a…4f76), finalized #4200 (0x79ee…2eec), ⬇ 485.5kiB/s ⬆ 38.0kiB/s
2023-07-19 17:06:25 ⚙️  Syncing 745.8 bps, target=#8037658 (3 peers), best: #8100 (0xac9e…cba6), finalized #7800 (0xb93d…839f), ⬇ 334.1kiB/s ⬆ 24.0kiB/s
2023-07-19 17:06:30 ⚙️  Syncing 676.0 bps, target=#8037660 (3 peers), best: #11480 (0xbdbf…85f2), finalized #11400 (0x612b…7853), ⬇ 409.8kiB/s ⬆ 23.4kiB/s
2023-07-19 17:06:35 ⚙️  Syncing 596.8 bps, target=#8037661 (3 peers), best: #14465 (0xcce8…aadb), finalized #14400 (0x8f77…7e6b), ⬇ 356.1kiB/s ⬆ 24.5kiB/s
2023-07-19 17:06:40 ⚙️  Syncing 646.8 bps, target=#8037663 (3 peers), best: #17700 (0xf0a1…36d6), finalized #17408 (0x467b…63bf), ⬇ 372.7kiB/s ⬆ 9.2kiB/s
2023-07-19 17:06:45 ⚙️  Syncing 596.4 bps, target=#8037665 (3 peers), best: #20682 (0xcc4c…2ca9), finalized #20480 (0x1d99…7288), ⬇ 340.3kiB/s ⬆ 12.3kiB/s
2023-07-19 17:06:50 ⚙️  Syncing 560.2 bps, target=#8037666 (3 peers), best: #23485 (0x83ba…6fae), finalized #23400 (0xa031…a7e0), ⬇ 399.4kiB/s ⬆ 9.9kiB/s
2023-07-19 17:06:55 ⚙️  Syncing 575.0 bps, target=#8037668 (3 peers), best: #26362 (0xb11c…7fc4), finalized #26112 (0xbaa5…6c61), ⬇ 328.7kiB/s ⬆ 12.8kiB/s
2023-07-19 17:07:00 ⚙️  Syncing 579.4 bps, target=#8037670 (3 peers), best: #29259 (0xa287…cf05), finalized #29184 (0x7ac8…55cb), ⬇ 353.6kiB/s ⬆ 7.8kiB/s
2023-07-19 17:07:05 ⚙️  Syncing 595.4 bps, target=#8037671 (3 peers), best: #32237 (0xfc62…6b12), finalized #32100 (0x95cd…0c27), ⬇ 338.3kiB/s ⬆ 14.9kiB/s
2023-07-19 17:07:10 ⚙️  Syncing 590.2 bps, target=#8037673 (3 peers), best: #35191 (0x3b06…9e27), finalized #35100 (0xd461…5ab7), ⬇ 330.9kiB/s ⬆ 8.7kiB/s
```

When the chain data is completely synchronized, newly generated blocks will start to synchronize one by one at every block time as follows.

```sh
2023-07-19 08:08:09 ✨ Imported #5384451 (0xd7a8…011f)    
2023-07-19 08:08:10 💤 Idle (25 peers), best: #5384451 (0xd7a8…011f), finalized #5384449 (0x1ae1…fdf3), ⬇ 47.7kiB/s ⬆ 49.5kiB/s    
2023-07-19 08:08:12 ✨ Imported #5384452 (0x9bf4…9710)    
2023-07-19 08:08:15 ✨ Imported #5384453 (0x90af…653a)    
2023-07-19 08:08:15 💤 Idle (25 peers), best: #5384453 (0x90af…653a), finalized #5384450 (0x8026…f68a), ⬇ 37.3kiB/s ⬆ 36.9kiB/s    
2023-07-19 08:08:18 ✨ Imported #5384454 (0x5c80…9b84)    
2023-07-19 08:08:20 💤 Idle (25 peers), best: #5384454 (0x5c80…9b84), finalized #5384452 (0x9bf4…9710), ⬇ 38.0kiB/s ⬆ 46.4kiB/s    
2023-07-19 08:08:21 ✨ Imported #5384455 (0x91d0…de42)    
2023-07-19 08:08:24 ✨ Imported #5384456 (0xb7e0…832e)    
2023-07-19 08:08:25 💤 Idle (25 peers), best: #5384456 (0xb7e0…832e), finalized #5384454 (0x5c80…9b84), ⬇ 46.2kiB/s ⬆ 44.2kiB/s    
2023-07-19 08:08:27 ✨ Imported #5384457 (0xcc84…0e00)    
2023-07-19 08:08:30 ✨ Imported #5384458 (0xc499…2475)    
2023-07-19 08:08:30 💤 Idle (25 peers), best: #5384458 (0xc499…2475), finalized #5384455 (0x91d0…de42), ⬇ 28.5kiB/s ⬆ 44.0kiB/s    
```

## Key Setup and Bonding

The scripts that we provide to proceed with the remaining detailed setup processes are written in Node.js. Install the required packages and execute the following commands to receive the script.

```bash
# step 1. install node.js and npm
# skip this step if node.js & npm are already installed on your environment
sudo apt update
sudo apt install -y nodejs npm

# step 2. clone the bifrost node git repository
git clone https://github.com/bifrost-platform/bifrost-node

# step 3. install the required packages
cd bifrost-node/tools
npm install
```

We now proceed with the key setting required to allow the validator node to perform the process of block generation and finalization. From this step onwards, the chain data synchronization of the running node must be completed.

First, validator nodes essentially require two Ethereum-style accounts, the controller and stash accounts, and in the case of the full nodes, an additional relayer account is required. The stash account must have enough BFC to deposit as much as the initial self-bond, and the controller account only needs enough balance to pay for some transactions. If you need to create a new account, you can run the following commands. Make sure that you are in the `tools` directory.

```bash
# Generate validator accounts

# Case 1. generate accounts for basic nodes
npm run create_accounts

# Case 2. generate accounts for full nodes
npm run create_accounts -- --full
```

After executing the command, the available new validator accounts will be printed as follows. You must send enough BFC to each account that meets the requirements to proceed to the next process.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2Fn4LCAQNN1YFDqbxAcbmK%2Fsystemd1.png?alt=media&amp;token=b789f176-4597-4bbd-ba83-99ea9a81ca57" alt=""><figcaption></figcaption></figure>

Next, the validator node must issue and register session keys to be used in the consensus algorithm. The process can be performed by executing the following command.&#x20;

```bash
npm run set_session_keys -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY"
```

<details>

<summary>Example</summary>

```sh
npm run set_session_keys -- \
  --controllerPrivate 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133
```

</details>

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FeXqFwkSxiSwE8vev8ZA1%2Fdocker5.png?alt=media&amp;token=8326bc1f-03e5-4a76-99d7-2e7e37182fd2" alt=""><figcaption></figcaption></figure>

This command will generate three session keys for your node. Each key has their own purpose. `Aura` is for block creation, `grandpa` is for block finalization, and `ImOnline` is for node liveness. The generated keys will be stored in your chain data directory. The directory path will look like this: `/var/lib/bifrost-data/chains/{testnet|mainnet}/keystore`.

Finally, it is necessary to deposit the self-bonds of the validator node to form the initial voting power. The process can be performed by executing the following command.

```bash
# case 1. join as a basic node
npm run join_validator_candidates -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY" \
  --stashPrivate "YOUR_STASH_PRIVATE_KEY" \
  --bond "YOUR_SELF_BOND_AMOUNT_IN_BFC"

# case 2. join as a full node
npm run join_validator_candidates -- \
  --controllerPrivate "YOUR_CONTROLLER_PRIVATE_KEY" \
  --stashPrivate "YOUR_STASH_PRIVATE_KEY" \
  --relayerPrivate "YOUR_RELAYER_PRIVATE_KEY" \
  --bond "YOUR_SELF_BOND_AMOUNT_IN_BFC"
```

<details>

<summary>Example</summary>

```sh
npm run join_validator_candidates -- \
  --controllerPrivate 0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133 \
  --stashPrivate 0x234871e7f7520af0cfc9f8547057b283c628be93a90b393aa19be1279ee52b4a \
  --relayerPrivate 0xcc01ee486e8717dc3911ede9293b767e29ce66f5c987da45887cb61822700117 \
  --bond 1000
```

</details>

If all of the above processes have been successfully completed, the amount of BFC deposited from the stash account will be deducted from the wallet, and your controller account will participate in the active validator update process at the next round. You can check whether or not you successfully joined the validator pool on the following [page](https://www.bifrostnetwork.com/stake).

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FjD47ftBQjNUq6PyWHKym%2Fsystemd2.png?alt=media&amp;token=adffa98f-44bf-49c3-bbe9-11110d98a5de" alt=""><figcaption></figcaption></figure>

If the tier of the validator node to be operated is a full node, it must be operated with the relayer. The manual for relayer setup can be found in the "[Setting up a Relayer](/bifrost-network/running-a-node/guide-for-operators/setting-up-a-relayer/bifrost-relayer.rs)" section below.

## Update Node Client

As Bifrost Network development continues, it will sometimes be necessary to upgrade your node client. Node operators will be notified on our Discord channel or by personal contacts when upgrades are available and whether they are necessary (some client upgrades are optional).&#x20;

Before upgrading your node client, please keep a backup file of your chain data to prevent any further data, keys, or credential losses.

{% tabs %}
{% tab title="Testnet" %}

```bash
# Stop and delete bifrost-node binary
systemctl stop bifrost-node.service
rm /var/lib/bifrost-data/bifrost-node
rm /var/lib/bifrost-data/bifrost-testnet.json

# Download the latest bifrost-node binary and chain specification JSON file
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-testnet.json"

# Grant execute permission & move to chain data directory
chmod +x bifrost-node
chown BIFROST_SERVICE bifrost-node
mv bifrost-node /var/lib/bifrost-data
mv bifrost-testnet.json /var/lib/bifrost-data

systemctl restart bifrost-node.service
```

{% endtab %}

{% tab title="Mainnet" %}

```bash
# Stop and delete bifrost-node binary
systemctl stop bifrost-node.service
rm /var/lib/bifrost-data/bifrost-node
rm /var/lib/bifrost-data/bifrost-mainnet.json

# Download the latest bifrost-node binary and chain specification JSON file
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-mainnet.json"

# Grant execute permission & move to chain data directory
chmod +x bifrost-node
chown BIFROST_SERVICE bifrost-node
mv bifrost-node /var/lib/bifrost-data
mv bifrost-mainnet.json /var/lib/bifrost-data

systemctl restart bifrost-node.service
```

{% endtab %}
{% endtabs %}


# Setting up a Relayer


# bifrost-relayer.rs

## What is bifrost-relayer.rs?

We recently introduced a Rust implementation of the CCCP-Relayer for the Bifrost Network. The new relayer has been reengineered to enhance overall performance and robustness across multiple blockchains. It retains the same functions as the [Python version](https://github.com/bifrost-platform/bifrost-relayer.py), processing cross-chain transactions and facilitating data transfers (e.g., feeding price information) from one blockchain to another.

The following section will guide you through the setup process about the [Rust implementation](https://github.com/bifrost-platform/bifrost-relayer.rs) of the Bifrost network's relayer.

## Install Requirements

To initiate the `bifrost-relayer`, certain dependencies must be manually installed. Both the executable binary file and the configuration YAML file are essential for all environments and operators.

First, install the latest `bifrost-relayer` release binary. You can check the latest releases by going to our GitHub repository under the [releases](https://github.com/bifrost-platform/bifrost-relayer.rs/releases) page.

```sh
wget "https://github.com/bifrost-platform/bifrost-relayer.rs/releases/latest/download/bifrost-relayer"
```

In order to execute the binary, the permission of the file has to be updated.

```sh
chmod +x bifrost-relayer
```

Then, install the configuration YAML file. This file serves as an example for a quick start. Given the minor differences between Testnet and Mainnet environments, it's crucial to use the appropriate file for the corresponding network.

```sh
# First create a directory to save your configuration file
mkdir configs && cd configs

# For mainnet only
wget "https://github.com/bifrost-platform/bifrost-relayer.rs/releases/latest/download/config.mainnet.yaml"

# For testnet only
wget "https://github.com/bifrost-platform/bifrost-relayer.rs/releases/latest/download/config.testnet.yaml"
```

## Configuration Setup

Next, the configuration YAML file contains certain parameters that the operator has to set. For instance, variables such as your relayer private key and each EVM provider's RPC endpoints depends to the operator itself, thus these values should be manually set.

You should prepare RPC endpoints for the following blockchain networks. There are two options for this: 1) operating your own blockchains nodes, or 2) utilizing services that offers RPC endpoints. You can find node providers on the links below. **It’s crucial that each node must be archive-mode enabled.**

* [Bifrost](https://docs.bifrostnetwork.com/bifrost-network/running-a-node/guide-for-operators/setting-up-a-validator-node) (**Must be priorly self-operating and fully synced**)
* [Ethereum](https://ethereum.org/en/developers/docs/nodes-and-clients/nodes-as-a-service/#popular-node-services)
* [Binance Smart Chain](https://docs.bnbchain.org/docs/rpc)
* [Polygon](https://wiki.polygon.technology/docs/pos/reference/rpc-endpoints/)
* [Base](https://docs.base.org/tools/node-providers/)
* [Arbitrum](https://docs.arbitrum.io/node-running/node-providers)
* [Bitcoin](https://bitcoin.org/en/full-node)
* [Core](https://docs.coredao.org/docs/Dev-Guide/rpc-list)
* [Oasys](https://docs.oasys.games/docs/staking/rpc-endpoint/1-1-rpc-endpoint)

### Configuration Templates

<details>

<summary>config.mainnet.yaml</summary>

```yaml
system:
  debug_mode: false

signer_config:
  # Two parameters below are optional, but one of them must be provided.
  # `kms_key_id` has higher priority than `private_key`.
  - kms_key_id: "<YOUR_KMS_KEY_ID_FOR_SIGNER>"
    private_key: "<YOUR_RELAYER_PRIVATE_KEY>"

keystore_config:
  path: "<YOUR_KEYSTORE_PATH>"
  # Two parameters below are optional, but one of them must be provided.
  # `kms_key_id` has higher priority than `password`.
  kms_key_id: "<YOUR_KMS_KEY_ID_FOR_KEYSTORE>"
  password: "<YOUR_KEYSTORE_PASSWORD>"

btc_provider:
  id: 10000
  chain: "main"
  provider: "<YOUR_BITCOIN_RPC_ENDPOINT>"
  call_interval: 10000
  block_confirmations: 2

evm_providers:
  - name: "bifrost"
    id: 3068
    provider: "<YOUR_BIFROST_RPC_ENDPOINT>"
    call_interval: 3000
    block_confirmations: 3
    is_native: true
    is_relay_target: true
    socket_address: "0xd551F33Ca8eCb0Be83d8799D9C68a368BA36Dd52"
    authority_address: "0x0000000000000000000000000000000000000400"
    relayer_manager_address: "0x0000000000000000000000000000000000002000"
    bitcoin_socket_address: "0x73A9E443F51eE40C1469A740D9CCf0118e8FD9ca"
    socket_queue_address: "0x0000000000000000000000000000000000000101"
    registration_pool_address: "0x0000000000000000000000000000000000000100"
    relay_executive_address: "0x0000000000000000000000000000000000000803"
    blaze_address: "0x0000000000000000000000000000000000000102"
  - name: "ethereum"
    id: 1
    provider: "<YOUR_ETHEREUM_RPC_ENDPOINT>"
    call_interval: 12000
    block_confirmations: 1
    is_relay_target: false
    eip1559: true
    socket_address: "0x4A31FfeAc276CC5e508cAC0568d932d398C4DD84"
    authority_address: "0xAdcaa90cabDc730855064d5b0f5242c16A9B7E10"
    chainlink_usdc_usd_address: "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6"
    chainlink_usdt_usd_address: "0x3E7d1eAB13ad0104d2750B8863b489D65364e32D"
    chainlink_dai_usd_address: "0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9"
    chainlink_btc_usd_address: "0xf4030086522a5beea4988f8ca5b36dbc97bee88c"
    chainlink_wbtc_usd_address: "0xfdFD9C85aD200c506Cf9e21F1FD8dd01932FBB23"
    chainlink_cbbtc_usd_address: "0x2665701293fCbEB223D11A08D826563EDcCE423A"
  - name: "bsc"
    id: 56
    provider: "<YOUR_BSC_RPC_ENDPOINT>"
    call_interval: 3000
    block_confirmations: 5
    is_relay_target: false
    eip1559: true
    socket_address: "0xb5Fa48E8B9b89760a9f9176388D1B64A8D4968dF"
    authority_address: "0xF0500d77d5446665314722b963ab1F71872063E9"
  - name: "polygon"
    id: 137
    provider: "<YOUR_POLYGON_RPC_ENDPOINT>"
    call_interval: 2000
    block_confirmations: 7
    is_relay_target: false
    eip1559: true
    socket_address: "0x050606CC2Bcd9504991Be2c309D6c6c832Bb5bd0"
    authority_address: "0x7F48909fBd1E38f1e05B5E326A44175fc2462B13"
  - name: "base"
    id: 8453
    provider: "<YOUR_BASE_RPC_ENDPOINT>"
    call_interval: 2000
    block_confirmations: 7
    is_relay_target: false
    eip1559: true
    socket_address: "0xAe172D8c5E428D4b7C70f9E593b207F9daC9BF3e"
    authority_address: "0x4C7a44F3FB37A53F33D3fe3cCdE97A444F105239"
  - name: "arbitrum"
    id: 42161
    provider: "<YOUR_ARBITRUM_ONE_RPC_ENDPOINT>"
    call_interval: 2000
    block_confirmations: 5
    get_logs_batch_size: 8
    is_relay_target: false
    eip1559: true
    socket_address: "0xac1552e30857A814a225BAa81145bcB071B46DDd"
    authority_address: "0xA069a57426Cd4c53925c1847Bec01aAB832A5118"
  - name: "core"
    id: 1116
    provider: "<YOUR_CORE_RPC_ENDPOINT>"
    call_interval: 3000
    block_confirmations: 3
    is_relay_target: false
    eip1559: false
    socket_address: "0x4C7a44F3FB37A53F33D3fe3cCdE97A444F105239"
    authority_address: "0xA069a57426Cd4c53925c1847Bec01aAB832A5118"
  - name: "oasys"
    id: 248
    provider: "<YOUR_OASYS_RPC_ENDPOINT>"
    call_interval: 6000
    block_confirmations: 3
    is_relay_target: false
    eip1559: true
    socket_address: "0x4C7a44F3FB37A53F33D3fe3cCdE97A444F105239"
    authority_address: "0x48820089C1d4f5d768f6800CF647b4f5b8675CFA"

handler_configs:
  - handler_type: Socket
    watch_list: [3068, 1, 56, 137, 8453, 42161, 1116, 248]
  - handler_type: Roundup
    watch_list: [3068]

###  The items below are optional. ###

bootstrap_config:
  is_enabled: true
  round_offset: 3
  btc_block_offset: 3

sentry_config:
  environment: "<YOUR_SENTRY_ENVIRONMENT>"
  is_enabled: false
  dsn: "<YOUR_SENTRY_DSN>"

prometheus_config:
  is_enabled: false
  is_external: false
  port: 8000
```

</details>

<details>

<summary>config.testnet.yaml</summary>

```yaml
system:
  debug_mode: false

signer_config:
  # Two parameters below are optional, but one of them must be provided.
  # `kms_key_id` has higher priority than `private_key`.
  - kms_key_id: "<YOUR_KMS_KEY_ID_FOR_SIGNER>"
    private_key: "<YOUR_RELAYER_PRIVATE_KEY>"

keystore_config:
  path: "<YOUR_KEYSTORE_PATH>"
  # Two parameters below are optional, but one of them must be provided.
  # `kms_key_id` has higher priority than `password`.
  kms_key_id: "<YOUR_KMS_KEY_ID_FOR_KEYSTORE>"
  password: "<YOUR_KEYSTORE_PASSWORD>"

btc_provider:
  id: 10001
  chain: "test"
  provider: "<YOUR_BITCOIN_RPC_ENDPOINT>"
  call_interval: 10000

evm_providers:
  - name: "bifrost-testnet"
    id: 49088
    provider: "<YOUR_BIFROST_TESTNET_RPC_ENDPOINT>"
    call_interval: 3000
    block_confirmations: 3
    is_native: true
    is_relay_target: true
    socket_address: "0x0218371b18340aBD460961bdF3Bd5F01858dAB53"
    authority_address: "0x0000000000000000000000000000000000000400"
    relayer_manager_address: "0x0000000000000000000000000000000000002000"
    bitcoin_socket_address: "0xc292D9d5c31D5246cfAC67ba91202bbCF0AA8108"
    socket_queue_address: "0x0000000000000000000000000000000000000101"
    registration_pool_address: "0x0000000000000000000000000000000000000100"
    relay_executive_address: "0x0000000000000000000000000000000000000803"
    blaze_address: "0x0000000000000000000000000000000000000102"
  - name: "sepolia"
    id: 11155111
    provider: "<YOUR_SEPOLIA_RPC_ENDPOINT>"
    call_interval: 12000
    block_confirmations: 1
    is_relay_target: false
    eip1559: true
    socket_address: "0xdAcc4aeea580F782bB991eA862e1a57827Ea9D68"
    authority_address: "0xff95B9861eE5d44eC0b489B0DCB73932c7C7074B"
  - name: "bsc-testnet"
    id: 97
    provider: "<YOUR_BSC_TESTNET_RPC_ENDPOINT>"
    call_interval: 3000
    block_confirmations: 5
    is_relay_target: false
    eip1559: true
    socket_address: "0x8039c3AD8ED55509fD3f6Daa78867923fDe6E61c"
    authority_address: "0xCf9f6428A309b6652a1dfaA4d8aB8B61C9c7E8CF"
    chainlink_usdc_usd_address: "0x90c069C4538adAc136E051052E14c1cD799C41B7"
    chainlink_usdt_usd_address: "0xEca2605f0BCF2BA5966372C99837b1F182d3D620"
    chainlink_dai_usd_address: "0xE4eE17114774713d2De0eC0f035d4F7665fc025D"
    chainlink_btc_usd_address: "0x5741306c21795FdCBb9b265Ea0255F499DFe515C"
    chainlink_wbtc_usd_address: "0x5741306c21795FdCBb9b265Ea0255F499DFe515C"
  - name: "base-sepolia"
    id: 84532
    provider: "<YOUR_BASE_SEPOLIA_RPC_ENDPOINT>"
    call_interval: 2000
    block_confirmations: 7
    is_relay_target: false
    eip1559: true
    socket_address: "0xdAcc4aeea580F782bB991eA862e1a57827Ea9D68"
    authority_address: "0x15EDC0c65004548fa787Bc01e533366674946C5F"
  - name: "arbitrum-sepolia"
    id: 421614
    provider: "<YOUR_ARBITRUM_SEPOLIA_RPC_ENDPOINT>"
    call_interval: 2000
    block_confirmations: 5
    get_logs_batch_size: 8
    is_relay_target: false
    eip1559: true
    socket_address: "0xd1E060FD930B75DA9A709c91E6Ad03B330Fb2950"
    authority_address: "0x4dA97eCD85d4EE00E26C5f3aF21e6Da7bc3F71e2"

handler_configs:
  - handler_type: Socket
    watch_list: [49088, 11155111, 97, 84532, 421614]
  - handler_type: Roundup
    watch_list: [49088]

###  The items below are optional. ###

bootstrap_config:
  is_enabled: true
  round_offset: 3
  btc_block_offset: 3

sentry_config:
  environment: "<YOUR_SENTRY_ENVIRONMENT>"
  is_enabled: false
  dsn: "<YOUR_SENTRY_DSN>"

prometheus_config:
  is_enabled: false
  is_external: false
  port: 8000
```

</details>

### Configuration Parameters

The [following table](#parameter-descriptions) presents customizable parameters for the relayer. You can change each parameter according to your environment. However, we highly recommend to use the default values specified in the template except for fields that are not checked in the "Template Provided" column. Furthermore, "Template Provided" merely serves as an example, thus you must change the correct values for certain parameters (e.g., your private key).

**Generally, for safety and to prevent unexpected system malfunctions, you should refrain from altering parameters that are included in the YAML file but not explicitly specified.** If the network's self-monitoring mechanism detects a malfunction stemming from altered parameters, the offending relayer may be subject to slashing.

## Using Systemd

For operators who prefer on using Systemd, you should make a configuration file for the Systemd execution environment. First, create a configuration file in the following directory.

```sh
sudo vi /etc/systemd/system/bifrost-relayer.service
```

An example of the configuration is provided below. The following parameters should be set regarding to your setup environment.

* `<DIRECTORY_WHERE_BIFROST_RELAYER_LOCATES>` : The absolute path to the directory where the installed `bifrost-relayer` binary file locates.
* `<PATH_TO_BIFROST_RELAYER>` : The absolute path to the installed `bifrost-relayer` binary file.
* `<PATH_TO_CONFIG_FILE>` : The absolute path to the installed `config.testnet.yaml` or `config.mainnet.yaml`. This parameter will be the the value for the CLI option, `--chain`.

```systemd
[Unit]
Description=Bifrost Relayer Daemon
After=network.target
StartLimitIntervalSec=5

[Service]
Type=simple
Restart=always
RestartSec=30
SyslogIdentifier=bifrost-relayer
SyslogFacility=local7
WorkingDirectory=<DIRECTORY_WHERE_BIFROST_RELAYER_LOCATES>
ExecStart=<PATH_TO_BIFROST_RELAYER> --chain <mainnet|testnet|<PATH_TO_CONFIG_FILE>>
KillSignal=SIGHUP

[Install]
WantedBy=multi-user.target
```

<details>

<summary>Example</summary>

```systemd
[Unit]
Description=Bifrost Relayer Daemon
After=network.target
StartLimitIntervalSec=5

[Service]
Type=simple
Restart=always
RestartSec=30
SyslogIdentifier=bifrost-relayer
SyslogFacility=local7
WorkingDirectory=/home/ubuntu/example
ExecStart=/home/ubuntu/example/bifrost-relayer --chain /home/ubuntu/example/config.yaml
KillSignal=SIGHUP

[Install]
WantedBy=multi-user.target
```

</details>

### Run the Relayer Service <a href="#run-the-relayer-service" id="run-the-relayer-service"></a>

Now, the service can be started by executing the following commands. First, enable the service that will let it start automatically at every next system restart.

```sh
sudo systemctl enable bifrost-relayer
```

Then, start the Systemd service, executing instructions in the service’s configuration file, use the `start` command as mentioned below.

```sh
sudo systemctl start bifrost-relayer
```

And lastly, verify the service has successfully executed.

```sh
systemctl status bifrost-relayer
```

### Check Logs

To check your running `bifrost-relayer` service logs, execute the command below.

```sh
journalctl -f -u bifrost-relayer
```

Once the service has successfully started, the initial logs will show up similar as below.

```sh
2023-08-04T14:41:38 INFO  sc_sysinfo     ]💻 Operating system: macos
2023-08-04T14:41:38 INFO  sc_sysinfo     ]💻 CPU architecture: aarch64
2023-08-04T14:41:38 INFO  bifrost-relayer]-[main               ] Bifrost Relayer
2023-08-04T14:41:38 INFO  bifrost-relayer]-[main               ] ✌️  version 1.0.2-1053ac84663
2023-08-04T14:41:38 INFO  bifrost-relayer]-[main               ] ❤️  by bifrost-platform, 2023-2023
2023-08-04T14:41:38 INFO  bifrost-relayer]-[main               ] ⛓  Chain specification: testnet
2023-08-04T14:41:38 INFO  bifrost-relayer]-[main               ] 👤 Relayer: 0xf708d58820fa20405993e186a8b38fb777f3143a
2023-08-04T14:41:38 INFO  bifrost-relayer]-[main               ] 🔨 Relay Targets (Legacy): bifrost, bsc
2023-08-04T14:41:38 INFO  bifrost-relayer]-[main               ] 🔨 Relay Targets (EIP1559): ethereum, polygon
2023-08-04T14:41:38 INFO  bifrost        ]-[block-manager      ] 💤 Idle, best: #8495214
2023-08-04T14:41:38 INFO  ethereum       ]-[block-manager      ] 💤 Idle, best: #9459619
2023-08-04T14:41:38 INFO  polygon        ]-[block-manager      ] 💤 Idle, best: #38621155
2023-08-04T14:41:38 INFO  bsc            ]-[block-manager      ] 💤 Idle, best: #32143709
```

If the bootstrap configuration is enabled, it will then start to bootstrap historical events as below.

```sh
2023-07-14T16:00:35 INFO  bifrost        ]-[roundup-handler    ] ⚙️  [Bootstrap mode] Bootstrapping RoundUp events.
2023-07-14T16:00:35 INFO  bsc            ]-[bridge-handler     ] ⚙️  [Bootstrap mode] Bootstrapping Socket events.
2023-07-14T16:00:35 INFO  bifrost        ]-[bridge-handler     ] ⚙️  [Bootstrap mode] Bootstrapping Socket events.
2023-07-14T16:00:35 INFO  mumbai         ]-[bridge-handler     ] ⚙️  [Bootstrap mode] Bootstrapping Socket events.
2023-07-14T16:00:35 INFO  goerli         ]-[bridge-handler     ] ⚙️  [Bootstrap mode] Bootstrapping Socket events.
2023-07-14T16:00:37 INFO  bifrost        ]-[bridge-handler     ] ⚙️  [Bootstrap mode] Bootstrapping Socket events.
2023-07-14T16:00:37 INFO  bifrost-relayer]-[bridge-handler     ] ⚙️  [Bootstrap mode] Bootstrap process successfully ended.
```

After the initial launch and the bootstrap process ends, the system will wait until each chain has reached the block confirmations specified in your configuration YAML file. It will then import every new block on every interval as below.

```sh
2023-08-04T14:41:54 INFO  polygon        ]-[block-manager      ] ✨ Imported #38621155
2023-08-04T14:41:56 INFO  bifrost        ]-[block-manager      ] ✨ Imported #8495214
2023-08-04T14:41:56 INFO  polygon        ]-[block-manager      ] ✨ Imported #38621156
2023-08-04T14:41:57 INFO  bsc            ]-[block-manager      ] ✨ Imported #32143709
2023-08-04T14:41:58 INFO  polygon        ]-[block-manager      ] ✨ Imported #38621157
2023-08-04T14:41:59 INFO  bifrost        ]-[block-manager      ] ✨ Imported #8495215
2023-08-04T14:42:00 INFO  bsc            ]-[block-manager      ] ✨ Imported #32143710
2023-08-04T14:42:00 INFO  polygon        ]-[block-manager      ] ✨ Imported #38621158
2023-08-04T14:42:02 INFO  ethereum       ]-[block-manager      ] ✨ Imported #9459619
2023-08-04T14:42:02 INFO  bifrost        ]-[block-manager      ] ✨ Imported #8495216
2023-08-04T14:42:02 INFO  polygon        ]-[block-manager      ] ✨ Imported #38621159
2023-08-04T14:42:03 INFO  bsc            ]-[block-manager      ] ✨ Imported #32143711
```

If your relayer has met every system logs mentioned above, this means that it has successfully been launched and has started to operate in a healthy state.

### Upgrade Service

As the `bifrost-relayer` is under continuous development, there will be instances when it becomes necessary to upgrade your relayer service. When such upgrades become available, relayer operators will be notified either through our community channels or via direct communication. Please note that some upgrades may be optional rather than mandatory.

First, remove or backup the previous `bifrost-relayer` binary file.

```sh
rm <PATH_TO_BIFROST_RELAYER_BINARY>
```

Then, install the latest version of `bifrost-relayer` into the same directory and update permissions. (In case of directory changes, the Systemd configuration file should be modified as well)

```sh
chmod +x bifrost-relayer
```

At last, restart the Systemd service.

```sh
sudo systemctl restart bifrost-relayer
```

## Using Docker

For operators who prefer on using Docker, it must be pre-installed in your operating system. Once installed, you can proceed to the following steps.

To run the relayer as a Docker container, use the command as mentioned below.

* `<DIRECTORY_WHERE_CONFIG_FILE_LOCATES>` : The absolute path of the directory where the installed `config.testnet.yaml` or `config.mainnet.yaml` locates.
* `<YOUR_CONFIG_FILE_NAME>` : The file name of the installed configuration YAML file.
* `<YOUR_CONTAINER_NAME>` : Please set an explicit name for your relayer container.

```sh
docker run -d \
  --restart always \
  --network host \
  --mount type=bind,source=<DIRECTORY_WHERE_CONFIG_FILE_LOCATES>,target=/relayer/configs \
  --name <YOUR_CONTAINER_NAME> \
  thebifrost/bifrost-relayer.rs:latest --chain /relayer/configs/<YOUR_CONFIG_FILE_NAME>
```

<details>

<summary>Example</summary>

```sh
docker run -d \
  --restart always \
  --network host \
  --mount type=bind,source=/home/ubuntu/example,target=/relayer/configs \
  --name bifrost-relayer \
  thebifrost/bifrost-relayer.rs:latest --chain /relayer/configs/config.mainnet.yaml
```

</details>

### Check Logs

To check your running `bifrost-relayer` container logs, execute the command below.

```sh
docker logs -f <YOUR_CONTAINER_NAME>
```

### Upgrade Docker Image

As the `bifrost-relayer` is under continuous development, there will be instances when it becomes necessary to upgrade your relayer service. When such upgrades become available, relayer operators will be notified either through our community channels or via direct communication. Please note that some upgrades may be optional rather than mandatory.

First stop and remove your running relayer container.

```sh
docker stop "YOUR_CONTAINER_NAME"
docker rm "YOUR_CONTAINER_NAME"
```

Then, pull the latest `bifrost-relayer` Docker image.

```sh
docker pull thebifrost/bifrost-relayer.rs:latest
```

At last execute the following command below to start a new container.

```sh
docker run -d \
  --restart always \
  --network host \
  --mount type=bind,source=<DIRECTORY_WHERE_CONFIG_FILE_LOCATES>,target=/relayer/configs \
  --name <YOUR_CONTAINER_NAME> \
  thebifrost/bifrost-relayer.rs:latest --chain /relayer/configs/<YOUR_CONFIG_FILE_NAME>
```

## Parameter Descriptions

<table data-full-width="true"><thead><tr><th width="201">Name</th><th>Description</th><th>Example / Available Values</th><th width="122" data-type="checkbox">Required</th><th width="180" data-type="checkbox">Template Provided</th><th>Default</th></tr></thead><tbody><tr><td><code>system</code></td><td>System related parameters of the relayer.</td><td>-</td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>system.private_key</code></td><td>The private key of the relayer.</td><td><code>"0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133"</code></td><td>true</td><td>false</td><td>-</td></tr><tr><td><code>system.debug_mode</code></td><td>The flag that represents if the debug mode is enabled. If enabled, debug-level logs and sentry alerts will be enabled.</td><td><code>true</code> / <code>false</code></td><td>false</td><td>true</td><td><code>false</code></td></tr><tr><td><code>btc_provider</code></td><td>The parameters related to the Bitcoin chain provider.</td><td>-</td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>btc_provider.id</code></td><td>The unique ID of the Bitcoin chain.</td><td><ul><li><code>10000</code> (For Mainnet)</li><li><code>10001</code> (For Testnet)</li></ul></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>btc_provider.chain</code></td><td>The name of the Bitcoin chain.</td><td><ul><li><code>"main"</code> (For Mainnet)</li><li><code>"test"</code> (For Testnet)</li></ul></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>btc_provider.provider</code></td><td>The RPC endpoint of the Bitcoin chain.</td><td>-</td><td>true</td><td>false</td><td>-</td></tr><tr><td><code>btc_provider.call_interval</code></td><td>The block synchronization interval in milliseconds. At every new interval, the system will synchronize every new block mined on the target chain.</td><td><code>10000</code></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>btc_provider.block_confirmations</code></td><td>The number of block confirmations required to synchronize a new block.</td><td><code>3</code></td><td>true</td><td>true</td><td><code>3</code></td></tr><tr><td><code>evm_providers</code></td><td>The parameters related to EVM chain providers.</td><td>-</td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>evm_providers.id</code></td><td>The unique ID of the chain.</td><td><code>3068</code></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>evm_providers.name</code></td><td>The name of the chain.</td><td><code>"bifrost"</code></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>evm_providers.provider</code></td><td>The RPC endpoint of the node. If the node is running, or is expected to be operated on the same server with the relayer, then set this value to the provided example.</td><td><code>"http://127.0.0.1:9933"</code></td><td>true</td><td>false</td><td>-</td></tr><tr><td><code>evm_providers.call_interval</code></td><td>The block synchronization interval in milliseconds. At every new interval, the system will synchronize every new block mined on the target chain.</td><td><code>1500</code></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>evm_providers.block_confirmations</code></td><td>The number of block confirmations required to synchronize a new block.</td><td><code>5</code></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>evm_providers.is_relay_target</code></td><td>The flag which represents whether the system will participate in external-chain CCCP actions. If this value is set to <code>true</code>, the system will try to execute transactions on the target chain, so sufficient balances are required. This value must be set to <code>true</code> if it is the Bifrost Network.</td><td><code>true</code> / <code>false</code></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>evm_providers.eip1559</code></td><td>The flag which represents whether the system will execute EIP-1559 transactions. If set to <code>false</code>, transactions will be executed by legacy types.</td><td><code>true</code> / <code>false</code></td><td>false</td><td>true</td><td><code>false</code></td></tr><tr><td><code>evm_providers.min_gas_price</code></td><td>The minimum gas price (in WEI) that the system will setup when executing legacy transactions. If the value is null, it will be dynamically set. This field only has effect when the <code>eip1559</code> parameter is disabled.</td><td><code>30000000000</code></td><td>false</td><td>true</td><td><code>0</code></td></tr><tr><td><code>evm_providers.min_priority_fee</code></td><td>The minimum priority fee (in WEI) that the system will setup when executing EIP-1559 transactions. If the value is null, it will be dynamically set. This field only has effect when the <code>eip1559</code> parameter is enabled.</td><td><code>30000000000</code></td><td>false</td><td>true</td><td><code>0</code></td></tr><tr><td><code>evm_providers.escalate_percentage</code></td><td>The percentage that will be used on gas price escalation to replace a transaction that is stuck in the mempool. This option will only have effect for legacy transactions.</td><td><code>15.0</code></td><td>false</td><td>false</td><td><code>15.0</code></td></tr><tr><td><code>evm_providers.is_initially_escalated</code></td><td>The flag whether if the gas price will be initially escalated. The <code>escalate_percentage</code> will be used on escalation. This option will only have effect for legacy transactions.</td><td><code>true</code> / <code>false</code></td><td>false</td><td>false</td><td><code>false</code></td></tr><tr><td><code>evm_providers.get_logs_batch_size</code></td><td>The batch size (=block range) used when requesting <code>eth_getLogs()</code>. If increased the RPC request ration will be reduced, however event processing will be delayed regarded to the configured value. Default size is set  to 1, which means it will be requested on every new block.</td><td><code>5</code></td><td>false</td><td>false</td><td><code>1</code></td></tr><tr><td><code>sentry_config</code></td><td>Sentry related parameters. If this section does not exist in your configuration file, Sentry will be disabled.</td><td>-</td><td>false</td><td>true</td><td><code>None</code></td></tr><tr><td><code>sentry_config.is_enabled</code></td><td>The flag which represents whether Sentry is enabled.</td><td>-</td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>sentry_config.environment</code></td><td>The identifier for the Sentry client. This value will be used to distinguish triggered alarms.</td><td><code>"mainnet"</code></td><td>false</td><td>true</td><td><code>""</code></td></tr><tr><td><code>sentry_config.dsn</code></td><td>The Sentry DSN. If the value has been set, error and warning alerts will be notified. If the value is empty, Sentry will be disabled.</td><td>-</td><td>false</td><td>false</td><td>-</td></tr><tr><td><code>prometheus_config</code></td><td>Prometheus related parameters. It this section does not exist in your configuration file, Prometheus will be disabled.</td><td>-</td><td>false</td><td>true</td><td><code>None</code></td></tr><tr><td><code>prometheus_config.is_enabled</code></td><td>The flag which represents whether Prometheus metric collection is enabled.</td><td><code>true</code> / <code>false</code></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>prometheus_config.is_external</code></td><td>The flag which represents whether the Prometheus server is exposed on all interfaces.</td><td><code>true</code> / <code>false</code></td><td>false</td><td>true</td><td><code>false</code></td></tr><tr><td><code>prometheus_config.port</code></td><td>The Prometheus exporter TCP port.</td><td><code>8000</code></td><td>false</td><td>true</td><td><code>8000</code></td></tr><tr><td><code>bootstrap_config</code></td><td>Bootstrap related parameters. Bootstrap is a process that will be executed whenever the relayer (re-)starts. It will collect historical CCCP events and let the relayer re-handle the event to prevent missed actions.</td><td>-</td><td>false</td><td>true</td><td><code>None</code></td></tr><tr><td><code>bootstrap_config.is_enabled</code></td><td>The flag which represents whether bootstrap is enabled</td><td><code>true</code> / <code>false</code></td><td>true</td><td>true</td><td>-</td></tr><tr><td><code>bootstrap_config.round_offset</code></td><td>The amount of rounds to search for missed events.</td><td><code>3</code></td><td>false</td><td>true</td><td><code>3</code></td></tr></tbody></table>


# Chain Data Snapshots

## **Chain Data Synchronization Using Snapshots**

Bifrost Network provides snapshots of the chain data. Snapshots are updated at regular intervals.

This allows node operators to spend less time on data synchronization and reduce the load on the network.

1. Follow the [link](https://github.com/bifrost-platform/bifrost-snapshots), and complete the snapshot download\&export process.
2. Return to the process in the operation manual once complete.


# Trouble Shooting


# Testnet Chain Sync Issue

{% hint style="info" %}
This guide will walk you through how to resolve the issue when your **Testnet** node has stopped to sync chain data at block **#336,000**.
{% endhint %}

<details>

<summary>Error logs that might have been printed</summary>

```sh
2022-10-23 01:41:12 Proposing failed: Import failed: Error at calling runtime api: Execution failed: Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed
WASM backtrace:

    0: 0x24bfd9 - <unknown>!rust_panic
    1: 0x24bfd2 - <unknown>!std::panicking::rust_panic_with_hook::hd20dbb32ccf2960c
    2: 0x24bc3d - <unknown>!std::panicking::begin_panic_handler::{{closure}}::h6f71c047f903cff6
    3: 0x24bb87 - <unknown>!std::sys_common::backtrace::__rust_end_short_backtrace::hbb6ee37c9cb141a4
    4: 0x24bc85 - <unknown>!rust_begin_unwind
    5: 0x1b2a32 - <unknown>!core::panicking::panic_fmt::ha6d5b6466ab38e11
    6: 0x1b2e05 - <unknown>!core::result::unwrap_failed::h7aa4a6c45486df8b
    7: 0xaa870 - <unknown>!<(TupleElement0,TupleElement1) as frame_support::traits::hooks::OnInitialize<BlockNumber>>::on_initialize::h93502e603e15f2d8
    8: 0x11fe6d - <unknown>!<(TupleElement0,TupleElement1) as frame_support::traits::hooks::OnInitialize<BlockNumber>>::on_initialize::had430e6d91ca4c07
    9: 0x41118 - <unknown>!<(TupleElement0,TupleElement1) as frame_support::traits::hooks::OnInitialize<BlockNumber>>::on_initialize::h58cc151aae952149
   10: 0xe7221 - <unknown>!<(TupleElement0,TupleElement1) as frame_support::traits::hooks::OnInitialize<BlockNumber>>::on_initialize::hedbe5eed270208e6
   11: 0x182c1c - <unknown>!frame_executive::Executive<System,Block,Context,UnsignedValidator,AllPalletsWithSystem,COnRuntimeUpgrade>::initialize_block::h8d01681df137b3e8
   12: 0x102be8 - <unknown>!Core_initialize_block
```

</details>

## **1. Synchronization Using Snapshot (Recommended)**

{% hint style="info" %}
Currently if your node is running in full-mode (non-archive mode), instead of this step you should follow to section [#id-2.-synchronization-from-the-genesis-block](#id-2.-synchronization-from-the-genesis-block "mention")
{% endhint %}

The Bifrost Network provides snapshots of the chain data. Snapshots are updated at regular intervals. This allows node operators to spend less time on data synchronization and reduce the load on the network.

1. Follow the [link](https://github.com/bifrost-platform/bifrost-snapshots), and complete the snapshot download & export process.
2. Return to the process in the operation manual once complete.

## **2. Synchronization from the Genesis Block**

This method does not require downloading snapshots. This section works for both archive and full modes.

#### 1. Block 0 to 336115

For initial synchronization, utilize [bifrost-node 1.0.2](https://github.com/bifrost-platform/bifrost-node/releases/tag/v1.0.2) up to at least block 336115.

```bash
wget "https://github.com/bifrost-platform/bifrost-node/releases/download/v1.0.2/bifrost-node"
wget "https://github.com/bifrost-platform/bifrost-node/releases/download/v1.0.2/bifrost-testnet.json"
chmod +x bifrost-node

mv bifrost-node bifrost-testnet.json <YOUR-BASE-PATH-DIRECTORY>
cd <YOUR-BASE-PATH-DIRECTORY>

# For archive-mode
./bifrost-node --base-path ./ --chain ./bifrost-testnet.json --port 30333 --pruning archive --runtime-cache-size 128
# For full-mode (remove --pruning option)
./bifrost-node --base-path ./ --chain ./bifrost-testnet.json --port 30333 --runtime-cache-size 128
```

After start running your node, it will start to synchronize chain data from the genesis block as below. (In some cases, error logs might be displayed, but for now, those are fine to ignore)

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FfEnNfImefd4ORmI35WSq%2FUntitled.png?alt=media&amp;token=5482f2e7-8db7-4dc7-9e17-8423f17a6391" alt=""><figcaption><p>Until the number following ‘best’ goes higher than 336115.</p></figcaption></figure>

#### 2. Block 336115 onwards

Once synchronization reaches block 336115, utilize [the latest version of bifrost-node](https://github.com/bifrost-platform/bifrost-node/releases).

```bash
# After terminate existing bifrost-node

cd <YOUR-BASE-PATH-DIRECTORY>
rm bifrost-node
wget https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-node
wget https://github.com/bifrost-platform/bifrost-node/releases/latest/download/bifrost-testnet.json
chmod +x bifrost-node

# For archive-mode (the option name for --pruning has changed to --state-pruning)
./bifrost-node --base-path ./ --chain ./bifrost-testnet.json --port 30333 --state-pruning archive --runtime-cache-size 128
# For full-mode (remove --state-pruning option)
./bifrost-node --base-path ./ --chain ./bifrost-testnet.json --port 30333 --runtime-cache-size 128
```

After restarting your node, in some cases, error logs might be displayed as before, however it is fine to ignore.

#### 3. Complete synchronization

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FaSOoRBiQgSzckVAJI8ez%2FUntitled%20(1).png?alt=media&amp;token=1dd81c0b-c655-47dc-a312-505b060cd7f3" alt=""><figcaption></figcaption></figure>

Synchronization is complete once “Syncing” does not appear in the log. Return to the process on the operation manual.


# System Monitoring

This section outlines how to monitor the status of the Bifrost Node and Relayer. It will be useful for debugging, adjusting, and understanding what actually happens in the Bifrost Node and Relayer.


# Prometheus and Grafana

The Bifrost node and relayer also supports system metric monitoring. This guide will walk you through how to setup [Prometheus](https://prometheus.io/) and [Grafana](https://grafana.com/) to monitor your node and relayer.

## Enable Prometheus

In order to let your Bifrost node and relayer to collect Prometheus metrics, it must be manually enabled. To enable the Prometheus server of your node, the following CLI flags has to be provided and then restarted.

* `--prometheus-external` : This exposes the Prometheus exporter on all interfaces.
* `--prometheus-port <PORT>` : The default port will be set to `9615`. However, if port changes are required, then this flag must be provided.

In case that you're operating a full-node, to enable the Prometheus server of your relayer, the following parameters of your configuration YAML file has to be updated as below and restarted.

```yaml
prometheus_config:
  is_enabled: true
  is_external: true
  port: 8000
```

If it has been successfully restarted, in both of your services the following log will be printed at the initial launch.

```sh
2023-07-14 18:24:54 〽️ Prometheus exporter started at 0.0.0.0:9615
```

## Using Systemd

This section contains how to install and setup Prometheus and Grafana by using Systemd.

### Installing Prometheus

First, create the directories required to store the configuration and executable files.

```sh
sudo mkdir /etc/prometheus
sudo mkdir /var/lib/prometheus
```

Then, update your OS and install the latest Prometheus. You can check the latest releases by going to their GitHub repository under the [releases](https://github.com/prometheus/prometheus/releases/) page.

```sh
sudo apt-get update && apt-get upgrade
wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz
tar xfz prometheus-*.tar.gz
cd prometheus-2.45.0.linux-amd64
```

Copy the executable files to the `/usr/local/bin/` directory.

```sh
sudo cp ./prometheus /usr/local/bin/
sudo cp ./promtool /usr/local/bin/
```

Copy the console files to the `/etc/prometheus` directory.

```sh
sudo cp -r ./consoles /etc/prometheus
sudo cp -r ./console_libraries /etc/prometheus
```

Once everything is done, remove the `prometheus` directory.

```sh
cd .. && rm -rf prometheus*
```

### Installing NodeExporter

Now, install the NodeExporter. You can check the latest releases by going to their Github repository under the [releases](https://github.com/prometheus/node_exporter/releases) page.

```sh
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.0/node_exporter-1.6.0.linux-amd64.tar.gz
tar xvf node_exporter-*.tar.gz
sudo cp ./node_exporter-*.linux-amd64/node_exporter /usr/local/bin/
rm -rf ./node_exporter*
```

### Installing AlertManager

First, create the directories required to store the configuration and executable files.

```sh
sudo mkdir /etc/alertmanager
```

Next, install the AlertManager. You can check the latest releases by going to their Github repository under the [releases](https://github.com/prometheus/alertmanager/releases) page.

```sh
wget https://github.com/prometheus/alertmanager/releases/download/v0.25.0/alertmanager-0.25.0.linux-amd64.tar.gz
tar xvf alertmanager-*.tar.gz
sudo cp ./alertmanager-*.linux-amd64/alertmanager /usr/local/bin/
sudo cp ./alertmanager-*.linux-amd64/amtool /usr/local/bin/
rm -rf ./alertmanager*
```

Install the AlertManager plugins required for Grafana.

```sh
sudo grafana-cli plugins install camptocamp-prometheus-alertmanager-datasource
```

### Configure Alert Rules

Create the `rules.yml` file that will give the rules for the AlertManager.

```sh
sudo vi /etc/prometheus/rules.yml
```

We are going to create 2 basic rules that will trigger an alert in case the instance is down or the CPU usage crosses 80%. Add the following lines and save the file.

```yaml
groups:
  - name: alert_rules
    rules:
      - alert: InstanceDown
        expr: up == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Instance $labels.instance down"
          description: "[{{ $labels.instance }}] of job [{{ $labels.job }}] has been down for more than 1 minute."

      - alert: HostHighCpuLoad
        expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[2m])) * 100) > 80
        for: 0m
        labels:
          severity: warning
        annotations:
          summary: Host high CPU load (instance bLd Kusama)
          description: "CPU load is > 80%\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
```

The `alertmanager.yml` file is used to set the external service that will be called when an alert is triggered. Here, we are going to use the Gmail notification.

{% hint style="info" %}
For Gmail notification, you will need to generate an app password. We recommend you to use a dedicated email address for your alerts. In order to set-up follow this [link](https://support.google.com/mail/answer/185833?hl=en).
{% endhint %}

Create the file in the following path.

```sh
sudo vi /etc/alertmanager/alertmanager.yml
```

And add the Gmail configuration to it and save the file as below.

```yaml
global:
  resolve_timeout: 1m

route:
  receiver: 'gmail-notifications'

receivers:
  - name: 'gmail-notifications'
    email_configs:
      - to: '' # receiver email
        from: '' # sender(monitoring system) gmail
        smarthost: 'smtp.gmail.com:587'
        auth_username: '' # sender(monitoring system) gmail
        auth_identity: '' # sender(monitoring system) gmail
        auth_password: '' # sender(monitoring system) gmail's app password <https://support.google.com/mail/answer/185833?hl=en>
        send_resolved: true
```

<details>

<summary>Example</summary>

```yaml
global:
  resolve_timeout: 1m

route:
  receiver: 'gmail-notifications'

receivers:
  - name: 'gmail-notifications'
    email_configs:
      - to: 'receiver-example@gmail.com'
        from: 'sender-example@gmail.com'
        smarthost: 'smtp.gmail.com:587'
        auth_username: 'sender-example@gmail.com'
        auth_identity: 'sender-example@gmail.com'
        auth_password: 'my-auth-password'
        send_resolved: true
```

</details>

### Configure Prometheus

In order to start Prometheus, it needs some configuration. Create a configuration yaml file in the following directory.

```sh
sudo vi /etc/prometheus/prometheus.yml
```

The configuration file should look as below.

<pre class="language-yaml"><code class="lang-yaml">global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "rules.yml"
  
<strong>alerting:
</strong>  alertmanagers:
    - static_configs:
        - targets:
            - "localhost:9093"

scrape_configs:
  - job_name: "prometheus"
    scrape_interval: 5s
    static_configs:
      - targets: [ "localhost:9090" ]
  - job_name: "bifrost_node"
    scrape_interval: 5s
    static_configs:
      - targets: [ "localhost:9615" ]
  - job_name: "node_exporter"
    scrape_interval: 5s
    static_configs:
      - targets: [ "localhost:9100" ]
  - job_name: "bifrost_relayer"
    scrape_interval: 5s
    static_configs:
      - targets: [ "localhost:8000" ]
</code></pre>

### Starting Prometheus

Next, the Systemd configuration should be set for Prometheus. Create a configuration file in the following directory.

```sh
sudo vi /etc/systemd/system/prometheus.service
```

The configuration file should look as below.

```systemd
[Unit]
Description=Prometheus Monitoring
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/prometheus \
  --config.file /etc/prometheus/prometheus.yml \
  --storage.tsdb.path /var/lib/prometheus/ \
  --web.console.templates=/etc/prometheus/consoles \
  --web.console.libraries=/etc/prometheus/console_libraries
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target
```

Now, enable and start the service.

```sh
sudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheus
```

To test out if it all successfully worked, access `YOUR_SERVER_IP_ADDRESS:9090`. If the Prometheus dashboard appears, it is good to go.

### Starting NodeExporter

The Systemd configuration should be set for the NodeExporter. Crate a configuration file in the following directory.

```sh
sudo vi /etc/systemd/system/node_exporter.service
```

The configuration file should look as below.

```systemd
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target

[Service] 
Type=simple
ExecStart=/usr/local/bin/node_exporter

[Install]
WantedBy=multi-user.target
```

Now, enable and start the service.

```sh
sudo systemctl enable node_exporter
sudo systemctl start node_exporter
```

### Starting AlertManager

The Systemd configuration should be set for the AlertManager. Crate a configuration file in the following directory.

```sh
sudo vi /etc/systemd/system/alertmanager.service
```

The configuration file should look as below.

```systemd
[Unit]
Description=AlertManager Server Service
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/alertmanager \
--config.file /etc/alertmanager/alertmanager.yml \
--storage.path /var/lib/alertmanager \
--web.external-url=http://localhost:9093 \
--cluster.advertise-address='0.0.0.0:9093'

[Install]
WantedBy=multi-user.target
```

Now, enable and start the service.

```sh
sudo systemctl enable alertmanager
sudo systemctl start alertmanager
```

### Installing Grafana

To visualize your Prometheus metrics, you should install Grafana, which queries the Prometheus server. The latest releases can be checked on their [download page](https://grafana.com/grafana/download). Execute the following commands to install the necessary dependencies.

```sh
sudo apt-get install -y adduser libfontconfig1
wget https://dl.grafana.com/enterprise/release/grafana-enterprise_10.0.1_amd64.deb
sudo dpkg -i grafana-enterprise_10.0.1_amd64.deb
```

### Starting Grafana

Then enable and start the service with default configurations.

```sh
sudo systemctl daemon-reload
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
```

You can now access it by going to `YOUR_SERVER_IP_ADDRESS:3000/login`. The default user and password is `admin/admin`.

## Using Docker

This section contains how to install and setup Prometheus and Grafana by using Docker.

### Requirements

First, Docker and Docker Compose should be installed in your server. Then you can download the `docker-compose.yml` file that is provided in Bifrost node's [Github](https://github.com/bifrost-platform/bifrost-node/blob/main/maintenance/docker-compose.yml) repository. Download the file by using the command below. The file will be located in the `maintenance` directory.

```sh
git clone https://github.com/bifrost-platform/bifrost-node.git
cd bifrost-node/maintenance
```

### Configure AlertManager

The alert rules are pre-defined in the `maintenance/prometheus/rules.yml` file. It contains 2 basic rules that will trigger an alert in case the instance is down or the CPU usage crosses 80%. The file will be provided as below.

```yaml
groups:
  - name: alert_rules
    rules:
      - alert: InstanceDown
        expr: up == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Instance $labels.instance down"
          description: "[{{ $labels.instance }}] of job [{{ $labels.job }}] has been down for more than 1 minute."

      - alert: HostHighCpuLoad
        expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[2m])) * 100) > 80
        for: 0m
        labels:
          severity: warning
        annotations:
          summary: Host high CPU load (instance bLd Kusama)
          description: "CPU load is > 80%\n  VALUE = {{ $value }}\n  LABELS: {{ $labels }}"
```

The `alertmanager.yml` file is used to set the external service that will be called when an alert is triggered. Here, we are going to use the Gmail notification.

{% hint style="info" %}
For Gmail notification, you will need to generate an app password. We recommend you to use a dedicated email address for your alerts. In order to set-up follow this [link](https://support.google.com/mail/answer/185833?hl=en).
{% endhint %}

The file locates in the `maintenance/alertmanager/alertmanager.yml` directory. Then, add the Gmail configuration to it and save the file as below.

```yaml
global:
  resolve_timeout: 1m

route:
  receiver: 'gmail-notifications'

receivers:
  - name: 'gmail-notifications'
    email_configs:
      - to: '' # receiver email
        from: '' # sender(monitoring system) gmail
        smarthost: 'smtp.gmail.com:587'
        auth_username: '' # sender(monitoring system) gmail
        auth_identity: '' # sender(monitoring system) gmail
        auth_password: '' # sender(monitoring system) gmail's app password <https://support.google.com/mail/answer/185833?hl=en>
        send_resolved: true
```

<details>

<summary>Example</summary>

```yaml
global:
  resolve_timeout: 1m

route:
  receiver: 'gmail-notifications'

receivers:
  - name: 'gmail-notifications'
    email_configs:
      - to: 'receiver-example@gmail.com'
        from: 'sender-example@gmail.com'
        smarthost: 'smtp.gmail.com:587'
        auth_username: 'sender-example@gmail.com'
        auth_identity: 'sender-example@gmail.com'
        auth_password: 'my-auth-password'
        send_resolved: true
```

</details>

### Configure Prometheus

In order to start Prometheus, it needs some configuration. The configuration file locates at `maintenance/prometheus/prometheus.yml`. For Full-Node operators who runs the node and relayer both, should manually uncomment the below "relayer" job.

```yaml
global:
  scrape_interval: 3s
  evaluation_interval: 3s

rule_files:
  - "rules.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - "alertmanager:9093"

scrape_configs:
  - job_name: "prometheus"
    scrape_interval: 3s
    static_configs:
      - targets: ["localhost:9090"]
  - job_name: "bifrost_node"
    scrape_interval: 3s
    static_configs:
      - targets: ["host.docker.internal:9615"]
  - job_name: "node_exporter"
    scrape_interval: 3s
    static_configs:
      - targets: ["node-exporter:9100"]
  # - job_name: "bifrost_relayer"
  #   scrape_interval: 3s
  #   static_configs:
  #     - targets: ["host.docker.internal:8000"]
```

### Run Docker Containers

If you have followed every processes above, return to the `maintenance` directory and execute the following command.

```sh
docker compose up -d
```

You can now access it by going to `YOUR_SERVER_IP_ADDRESS:3000/login`. The default user and password is `admin/admin`.

## Datasource Configuration

If it is all set, create a new Prometheus datasource and input the `URL` as `http://localhost:9090` and then click “Save & Test” as below.

{% hint style="info" %}
For Docker users, the URL should be set to `http://prometheus:9090`.
{% endhint %}

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F59F8dsFi5IBBxkpU9GCE%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.41.32.png?alt=media&amp;token=2cc328a2-9bfd-427f-b4d4-1ca8a0aab844" alt=""><figcaption></figcaption></figure>

Then, create a new Prometheus AlertManager datasource and input the URL as `http://localhost:9093` and then click "Save & Test" as below.

{% hint style="info" %}
For Docker users, the URL should be set to `http://alertmanager:9093`.
{% endhint %}

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FQxZhoFCuIL12kX8jx3Rt%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.42.25.png?alt=media&amp;token=f92b0d02-f7dc-44b8-8246-e3ff0c846e2d" alt=""><figcaption></figcaption></figure>

Next, the dashboard has to be imported. Access the "Dashboards" tab and click on "New" to import the dashboard as below.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FRnIInJUWMMLZj79fGnQ5%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.45.24.png?alt=media&amp;token=4f440318-02ea-43ae-87b1-8543cacb0d9c" alt=""><figcaption></figcaption></figure>

Now, in the "Import via grafana.com" section, input the dashboard ID as `19207` and then click "Load" to continue.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FAtLN5CtqGFOtE2ZasD4s%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.46.24.png?alt=media&amp;token=e9e62275-abe2-460c-a4e5-542cd208367c" alt=""><figcaption></figcaption></figure>

If it has been successfully loaded, set the correct datasources that you have just created before. The Prometheus and the AlertManager has to be set correctly. Then click "Import" to continue.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FzHjv0caK87Qy09GRcTQ0%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.48.39.png?alt=media&amp;token=10b3a909-578d-4ff6-ae16-cc84c42d051f" alt=""><figcaption></figcaption></figure>

In the meantime, if your node and relayer is running in the background, the collected metrics will be visualized as below.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FMcwa6vVMrwMRtzq9xXq9%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.50.54.png?alt=media&amp;token=efba97dd-e4ce-4255-898b-8638563fcfb3" alt=""><figcaption></figcaption></figure>


# Sentry

This guide will walk you through how to setup [Sentry](https://sentry.io/) to track errors and issues of your Bifrost relayer.

## Sentry Setup

To setup Sentry, you should first create an account and login to [https://sentry.io](https://sentry.io/). Then, you will be redirected to your Sentry dashboard. You will now have to create a new project for your Bifrost relayer. Access the “Projects” tab and then create a new project as below. You should set the platform to "RUST". However the alert frequency and project name is freely available to be customized.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FqkOQG5hJAPfnYlaER6CC%2Fimage.png?alt=media&amp;token=d71ab69d-6d71-4506-862e-f63162b71298" alt=""><figcaption></figcaption></figure>

You will now see your created project in the “Projects” tab. Access to your new project and go to the settings tab. Then on the left-hand side, you will see “Client Keys (DSN)” tab. On the page, you will see your project’s DSN key. Copy and paste your DSN key to `sentry_config.dsn` in your relayer’s configuration YAML file, and then restart the service.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F3vEAqqaemOKRa5I3T6ul%2Fimage.png?alt=media&amp;token=26bcdb14-84e5-49d2-a240-35a99cbf2af6" alt=""><figcaption></figcaption></figure>

Sentry is now ready to go. Whenever any new issue occurs, the error information will be displayed in your project’s dashboard and alerts will be notified to your target destination (Slack, Email, etc).


# Nominators

Nominators are one type of participant in the staking subsystem of Polkadot. They are responsible for appointing their stake to the validators who are the second type of participant. By appointing their stake, they are able to elect the active set of validators and share in the rewards that are paid out.

While the validators are active participants in the network that engage in the block production and finality mechanisms, nominators take a slightly more passive role. Being a nominator does not require running a node of your own or worrying about online uptime. However, a good nominator performs due diligence on the validators that they elect. When looking for validators to nominate, a nominator should pay attention to their own reward percentage for nominating a specific validator.

Nominators are recommended to set up separate [stash and controller accounts.](/bifrost-network/running-a-node#controller-and-stash-keys)

<br>


# Developer Documentations


# Ethereum API

The Bifrost Network has an Ethereum-like API that is fully compatible with Ethereum-style JSON RPC invocations. Therefore, developers constructing DApps on the Bifrost Network can utilize any development tool compatible with Ethereum.

###


# Ethereum Precompiled Contracts

The Bifrost Network supports the standard precompiled contract installed on the Ethereum mainnet. The following is the table of addresses of the implemented precompiled contracts.

#### ECRECOVER

It returns the signer address of the ecdsa signature (v, r, s) if the signature is valid. It can be called directly in Solidity code.

```solidity
// contract address: 0x0000000000000000000000000000000000000001
function ecrecover(bytes32 data, bytes32 v, bytes32 r, bytes32 s) returns (address);
```

#### SHA256

It returns the keccak-hash value of the data. It can be called directly in Solidity code.

```solidity
// contract address: 0x0000000000000000000000000000000000000002
function sha256(bytes data) returns (bytes32);
```

#### RIPEMD160

It returns the ripemd160-hash value of the data. It can be called directly in Solidity code.

```solidity
// contract address: 0x0000000000000000000000000000000000000003
function ripemd160(bytes data) returns (bytes32);
```

#### Identity

Also known as datacopy, this function serves as a cost-efficient way to copy data in memory. Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000004
contract Identity{

    bytes public memoryStored;

    function callDatacopy(bytes memory data) public returns (bytes memory) {
        bytes memory result = new bytes(data.length);
        assembly {
            let len := mload(data)
            if iszero(call(gas(), 0x04, 0, add(data, 0x20), len, add(result,0x20), len)) {
                invalid()
            }
        }

        memoryStored = result;

        return result;
    }
}
```

#### Modular Exponentiation

This function calculates the remainder when an integer `b`(base) is raised to the `e`-th power(the exponent) and is divided by a positive integer `m`(the modulus). Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000005
contract ModularCheck {

    uint public checkResult;

    // Function to Verify ModExp Result
    function verify( uint _base, uint _exp, uint _modulus) public {
        checkResult = modExp(_base, _exp, _modulus);
    }

    function modExp(uint256 _b, uint256 _e, uint256 _m) public returns (uint256 result) {
        assembly {
            // Free memory pointer
            let pointer := mload(0x40)
            // Define length of base, exponent and modulus. 0x20 == 32 bytes
            mstore(pointer, 0x20)
            mstore(add(pointer, 0x20), 0x20)
            mstore(add(pointer, 0x40), 0x20)
            // Define variables base, exponent and modulus
            mstore(add(pointer, 0x60), _b)
            mstore(add(pointer, 0x80), _e)
            mstore(add(pointer, 0xa0), _m)
            // Store the result
            let value := mload(0xc0)
            // Call the precompiled contract 0x05 = bigModExp
            if iszero(call(not(0), 0x05, 0, pointer, 0xc0, value, 0x20)) {
                revert(0, 0)
            }
            result := mload(value)
        }
    }
}
```

#### BN128Add

The `BN128Add` precompiled contract implements a native elliptic curve point addition. It returns an elliptic curve point representing `(ax, ay) + (bx, by)` such that `(ax, ay)` and `(bx, by)` are valid points on the curve `BN256`. Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000006
contract Precompiles {
    function callBn256Add(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by) public returns (bytes32[2] memory result) {
        bytes32[4] memory input;
        input[0] = ax;
        input[1] = ay;
        input[2] = bx;
        input[3] = by;
        assembly {
            let success := call(gas, 0x06, 0, input, 0x80, result, 0x40)
            switch success
            case 0 {
                revert(0,0)
            }
        }
    }
}
```

#### BN128Mul

The `BN128Mul` precompiled contract implements a native elliptic curve multiplication with a scalar value. It returns an elliptic curve point representing `scalar * (x, y)` such that `(x, y)` is a valid curve point on the curve `BN256`. Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000007
contract Precompiles {
    function callBn256ScalarMul(bytes32 x, bytes32 y, bytes32 scalar) public returns (bytes32[2] memory result) {
        bytes32[3] memory input;
        input[0] = x;
        input[1] = y;
        input[2] = scalar;
        assembly {
            let success := call(gas, 0x07, 0, input, 0x60, result, 0x40)
            switch success
            case 0 {
                revert(0,0)
            }
        }
    }
}
```

#### BN128Pairing

The `BN128Pairing` precompile implements elliptic curve paring operation to perform zkSNARK verification. For more information, check out the [EIP-197 standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md). Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000008
contract Precompiles {
    function callBn256Pairing(bytes memory input) public returns (bytes32 result) {
        // input is a serialized bytes stream of (a1, b1, a2, b2, ..., ak, bk) from (G_1 x G_2)^k
        uint256 len = input.length;
        require(len % 192 == 0);
        assembly {
            let memPtr := mload(0x40)
            let success := call(gas, 0x08, 0, add(input, 0x20), len, memPtr, 0x20)
            switch success
            case 0 {
                revert(0,0)
            } default {
                result := mload(memPtr)
            }
        }
    }
}
```

#### Blake2F

This EIP will enable the `BLAKE2b` hash function and other higher-round 64-bit `BLAKE2` variants to run cost-effectively on the EVM, allowing easier interoperability between Ethereum and Zcash or any other Equihash-based PoW coin. For more information, check out the [EIP-152 standard](https://eips.ethereum.org/EIPS/eip-152). Since the Solidity compiler does not support this function, this function must be called by assembly as follows.

```solidity
// contract address: 0x0000000000000000000000000000000000000009
function callBlake2F(uint32 rounds, bytes32[2] memory h, bytes32[4] memory m, bytes8[2] memory t, bool f) public view returns (bytes32[2] memory) {
    bytes32[2] memory output;

    bytes memory args = abi.encodePacked(rounds, h[0], h[1], m[0], m[1], m[2], m[3], t[0], t[1], f);

    assembly {
        if iszero(staticcall(not(0), 0x09, add(args, 32), 0xd5, output, 0x40)) {
            revert(0, 0)
        }
    }

    return output;
}
```


# Libraries

Developers who want to construct DApps on the Bifrost Network can utilize any library that supports Ethereum. The following is a list of some of the supported libraries.

### Ether.js

The ethers.js library aims to be a complete and compact library for interacting with the Ethereum blockchain and its ecosystem. You can find more information in their [documentation](https://docs.ethers.io/).

### Web3.js/Web3.py

Web3.js has a longer history and more maintainers than Ether.js and it provides a single instantiated web3 object with methods for interacting with the blockchain.\
You can find more information in their [documentation](https://web3py.readthedocs.io/en/v5/).

### OpenZeppelin

[OpenZeppelin](https://openzeppelin.com/) is well known in the Ethereum developer community as their set of audited smart contracts and libraries has become a standard in the industry. For example, most of the tutorials that show developers how to deploy an ERC-20 token use OpenZeppelin contracts.\
You can find more information in their [documentation](https://docs.openzeppelin.com/openzeppelin/).

### Polkadot.js

For exceptional developers who require Substrate runtime, pallets, or client interactions for their DApp development, `polkadot.js` will be an optimal choice. You can find more information in their [documentation](https://polkadot.js.org/docs/api).


# Developer Environments

Developers who want to construct DApps on the Bifrost Network can select any development tool that supports Ethereum. The following is a list of some of the supported development environments.

### Remix

[Remix](https://remix-project.org/) is a rich toolset that can be used throughout the entire development process by users at any knowledge level, and is a great learning lab for teaching and experimenting with Ethereum.\
You can find more information in their [documentation](https://remix-ide.readthedocs.io/en/latest/index.html).

### Truffle

Truffle supports developers throughout the full lifecycle of their projects, whether they are looking to build on Ethereum, Hyperledger, Quorum, or any other supported platform from an ever-growing list. Paired with Ganache, a personal blockchain, and Drizzle, a front-end DApp development kit, the full Truffle suite of tools promises to be an end-to-end DApp development platform.\
You can find more information in their [documentation](https://trufflesuite.com/docs/).

### Brownie

Brownie is a Python-based development and testing framework for smart contracts targeting the Ethereum Virtual Machine. It has powerful debugging tools and a built-in console.\
You can find more information in their [documentation](https://eth-brownie.readthedocs.io/en/stable/).

### Hardhat

Hardhat is a development environment for Ethereum software. It consists of different components for editing, compiling, debugging, and deploying smart contracts and DApps, all of which work together to create a complete development environment.\
You can find more information in their [documentation](https://hardhat.org/docs).


# Bifrost Precompiled Contracts

The Bifrost Network provides several useful sets of precompiled contracts. These contracts are implemented in the network itself as a native implementation. The addresses from `0x01` through `0x09` are identical to the standard Ethereum precompiled contracts. The Bifrost Network additionally supports several custom precompiled contracts for technical features.


# Staking

Any network participant who desires to become a *validator,* should first join the *candidate pool* by bonding the required amount of BFC to the network. Users can also delegate their power (BFC) to nominate their desired *candidate*. Finally, at each new round, only the top `n` *candidates* will be selected as *validators* to produce blocks.

*Candidates* and *nominators* can perform all actions related to validator elections through the following ***BfcStaking*** contract.

## BfcStaking contract

* address: `0x0000000000000000000000000000000000000400`
* Since the Solidity compiler does not support this function, it is recommended to call a method through the interface below.

```solidity
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.0;

/**
 * @title The interface through which solidity contracts will interact with Bfc Staking
 * We follow this same interface including four-byte function selectors, in the precompile that
 * wraps the pallet
 * Address :    0x0000000000000000000000000000000000000400
 */

interface BfcStaking {
    struct candidate_meta_data {
        address candidate;
        address stash;
        uint256 bond;
        uint256 initial_bond;
        uint256 nomination_count;
        uint256 voting_power;
        uint256 lowest_top_nomination_amount;
        uint256 highest_bottom_nomination_amount;
        uint256 lowest_bottom_nomination_amount;
        uint256 top_capacity;
        uint256 bottom_capacity;
        uint256 status;
        bool is_selected;
        uint256 commission;
        uint256 last_block;
        uint256 blocks_produced;
        uint256 productivity;
        uint256 reward_dst;
        uint256 awarded_tokens;
        uint256 tier;
    }

    struct candidate_request_data {
        address candidate;
        uint256 amount;
        uint256 when_executable;
    }

    struct total_stake {
        uint256 total_self_bond;
        uint256 active_self_bond;
        uint256 total_nominations;
        uint256 total_top_nominations;
        uint256 total_bottom_nominations;
        uint256 active_nominations;
        uint256 active_top_nominations;
        uint256 active_bottom_nominations;
        uint256 total_nominators;
        uint256 total_top_nominators;
        uint256 total_bottom_nominators;
        uint256 active_nominators;
        uint256 active_top_nominators;
        uint256 active_bottom_nominators;
        uint256 total_stake;
        uint256 active_stake;
        uint256 total_voting_power;
        uint256 active_voting_power;
    }

    struct round_meta_data {
        uint256 current_round_index;
        uint256 first_session_index;
        uint256 current_session_index;
        uint256 first_round_block;
        uint256 first_session_block;
        uint256 current_block;
        uint256 round_length;
        uint256 session_length;
    }

    /// @dev Check whether the specified address is currently a staking nominator
    /// Selector: 8e5080e7
    /// @param nominator the address that we want to confirm is a nominator
    /// @return A boolean confirming whether the address is a nominator
    function is_nominator(address nominator) external view returns (bool);

    /// @dev Check whether the specified address is currently a validator candidate (full or basic)
    /// Selector: 5245c1e1
    /// @param candidate the address that we want to confirm is a validator andidate
    /// @param tier the type of the validator candidate (0: All, 1: Basic, 2: Full)
    /// @return A boolean confirming whether the address is a validator candidate
    function is_candidate(address candidate, uint256 tier)
        external
        view
        returns (bool);

    /// @dev Check whether the specified address is currently a part of the active set (full or basic)
    /// Selector: 4a079cfd
    /// @param candidate the address that we want to confirm is a part of the active set
    /// @param tier the type of the validator candidate (0: All, 1: Basic, 2: Full)
    /// @return A boolean confirming whether the address is a part of the active set
    function is_selected_candidate(address candidate, uint256 tier)
        external
        view
        returns (bool);

    /// @dev Check whether the specified address elements is currently a part of the active set
    /// Selector: 044527bd
    /// @param candidates the address array that we want to confirm is a part of the active set
    /// @param tier the type of the validator candidate (0: All, 1: Basic, 2: Full)
    /// @return A boolean confirming whether the address array is a part of the active set
    function is_selected_candidates(address[] calldata candidates, uint256 tier)
        external
        view
        returns (bool);

    /// @dev Check whether every specified address element is currently the active set (full or basic)
    /// Selector: 2e8c2a6a
    /// @param candidates the address array that we want to confirm is the active set
    /// @param tier the type of the validator candidate (0: All, 1: Basic, 2: Full)
    /// @return A boolean confirming whether the address array is the active set
    function is_complete_selected_candidates(
        address[] calldata candidates,
        uint256 tier
    ) external view returns (bool);

    /// @dev Check whether the specified address was a part of the given round active set
    /// Selector: 0b32e591
    /// @param round_index the round index that we want to confirm
    /// @param candidate the address that we want to confirm is the active set
    /// @return A boolean confirming whether the address was in the active set
    function is_previous_selected_candidate(
        uint256 round_index,
        address candidate
    ) external view returns (bool);

    /// @dev Check whether the specified address array was a part of the given round active set
    /// Selector: e200c8e3
    /// @param round_index the round index that we want to confirm
    /// @param candidates the address array that we want to confirm is the active set
    /// @return A boolean confirming whether the address array was in the active set
    function is_previous_selected_candidates(
        uint256 round_index,
        address[] calldata candidates
    ) external view returns (bool);

    /// @dev Get the current rounds info
    /// Selector: f8aa8ddd
    /// @return The current rounds index, first session index, current session index,
    ///         first round block, first session block, current block, round length, session length
    function round_info() external view returns (round_meta_data memory);

    /// @dev Get the current rounds index
    /// Selector: 6f31dd98
    /// @return The current rounds index
    function latest_round() external view returns (uint256);

    /// @dev Get the current rounds active validator sets majority
    /// Selector: b6e54bdf
    /// @return The current rounds majority
    function majority() external view returns (uint256);

    /// @dev Get the given rounds active validator sets majority
    /// Selector: e0f9ab40
    /// @return The given rounds majority
    function previous_majority(uint256 round_index)
        external
        view
        returns (uint256);

    /// @dev Total points awarded to all validators in a particular round
    /// Selector: 9799b4e7
    /// @param round_index the round for which we are querying the points total
    /// @return The total points awarded to all validators in the round
    function points(uint256 round_index) external view returns (uint256);

    /// @dev awarded points to the given validator in the given round
    /// Selector: 59a595fb
    /// @param round_index the round for which we are querying the points
    /// @return The awarded points to the validator in the given round
    function validator_points(uint256 round_index, address validator)
        external
        view
        returns (uint256);

    /// @dev The amount of awarded tokens to validators and nominators since genesis
    /// Selector: 9ec5a894
    /// @return The total amount of awarded tokens
    function rewards() external view returns (uint256);

    /// @dev Total capital locked information of self-bonds and nominations of the given round
    /// Selector: b119ebfe
    /// @return The total locked information
    function total(uint256 round_index)
        external
        view
        returns (total_stake memory);

    /// @dev Stake annual inflation parameters
    /// Selector: 10db2de9
    /// @return The annual inflation parameters (min, ideal, max)
    function inflation_config()
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        );

    /// @dev Stake annual inflation rate
    /// Selector: 180692d0
    /// @return The annual inflation rate according to the current stake amount
    function inflation_rate() external view returns (uint256);

    /// @dev The estimated yearly return
    /// Selector: fd0c6dc1
    /// @return The estimated yearly return according to the requested data
    function estimated_yearly_return(
        address[] memory candidates,
        uint256[] memory amounts
    ) external view returns (uint256[] memory);

    /// @dev Get the minimum nomination amount
    /// Selector: c9f593b2
    /// @return The minimum nomination amount
    function min_nomination() external view returns (uint256);

    /// @dev Get the maximum nominations allowed per nominator
    /// Selector: 8b88f0e1
    /// @return The maximum nominations
    function max_nominations_per_nominator() external view returns (uint256);

    /// @dev Get the maximum top and bottom nominations counted per candidate
    /// Selector: 547eaba9
    /// @return The maximum top and bottom nominations per candidate (top, bottom)
    function max_nominations_per_candidate()
        external
        view
        returns (uint256, uint256);

    /// @dev Get the bond less delay information for candidates
    /// Selector: 7abd4bbb
    /// @return The bond less delay for candidates (`LeaveCandidatesDelay`, `CandidateBondLessDelay`)
    function candidate_bond_less_delay()
        external
        view
        returns (uint256, uint256);

    /// @dev Get the bond less delay information for nominators
    /// Selector: 804d185e
    /// @return The bond less delay for nominators (`LeaveNominatorsDelay`, `RevokeNominationDelay`, `NominationBondLessDelay`)
    function nominator_bond_less_delay()
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        );

    /// @dev Get the CandidateCount weight hint
    /// Selector: 4b1c4c29
    /// @return The CandidateCount weight hint
    function candidate_count() external view returns (uint256);

    /// @dev Get the current rounds selected candidates
    /// Selector: a5542eea
    /// @param tier the type of the validator candidate (0: All, 1: Basic, 2: Full)
    /// @return The list of the selected candidates
    function selected_candidates(uint256 tier)
        external
        view
        returns (address[] memory);

    /// @dev Get the previous selected candidates of the given round index
    /// Selector: d9c62dc8
    /// @return The list of the previous selected candidates
    function previous_selected_candidates(uint256 round_index)
        external
        view
        returns (address[] memory);

    /// @dev Get the current state of joined validator candidates
    /// Selector: 96b41b5b
    /// @return The list of the joined validator candidates
    function candidate_pool()
        external
        view
        returns (address[] memory, uint256[] memory);

    /// @dev Get the current state of the given candidate
    /// Selector: 36f3b497
    /// @param candidate the address for which we are querying the state
    /// @return The current state of the queried candidate
    function candidate_state(address candidate)
        external
        view
        returns (candidate_meta_data memory);

    /// @dev Get every candidate states
    /// Selector: 3b368c8c
    /// @param tier the type of the validator candidate (0: All, 1: Basic, 2: Full)
    /// @return An array of every candidate states
    function candidate_states(uint256 tier)
        external
        view
        returns (
            address[] memory,
            address[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            bool[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory
        );

    /// @dev Get every candidate states by the given selector
    /// Selector: d631e15c
    /// @param tier the type of the validator candidate (0: All, 1: Basic, 2: Full)
    /// @param is_selected the boolean for which it is selected for the current round
    /// @return An array of every candidate states that matches the selector
    function candidate_states_by_selection(uint256 tier, bool is_selected)
        external
        view
        returns (
            address[] memory,
            address[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            bool[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory
        );

    /// @dev Get the request status of the given candidate
    /// Selector: 2e388768
    /// @param candidate the address for which we are querying the state
    /// @return The current status of the queried candidate
    function candidate_request(address candidate)
        external
        view
        returns (candidate_request_data memory);

    /// @dev Get the top nominations of the given candidate
    /// Selector: 2a9cdf2b
    /// @param candidate the address for which we are querying the state
    /// @return The current status of the queried candidate
    function candidate_top_nominations(address candidate)
        external
        view
        returns (
            address,
            uint256,
            address[] memory,
            uint256[] memory
        );

    /// @dev Get the bottom nominations of the given candidate
    /// Selector: 9be794c0
    /// @param candidate the address for which we are querying the state
    /// @return The current status of the queried candidate
    function candidate_bottom_nominations(address candidate)
        external
        view
        returns (
            address,
            uint256,
            address[] memory,
            uint256[] memory
        );

    /// @dev Get the CandidateNominationCount weight hint
    /// Selector: 1c8ad6fe
    /// @param candidate The address for which we are querying the nomination count
    /// @return The number of nominations backing the validator
    function candidate_nomination_count(address candidate)
        external
        view
        returns (uint256);

    /// @dev Get the current state of the given nominator
    /// Selector: 3f97be51
    /// @param nominator the address for which we are querying the state
    /// @return The current state of the queried nominator
    function nominator_state(address nominator)
        external
        view
        returns (
            address,
            uint256,
            uint256,
            uint256,
            uint256,
            address[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256,
            uint256,
            uint256[] memory
        );

    /// @dev Get the pending requests of the given nominator
    /// Selector: 24f81326
    /// @param nominator the address for which we are querying the state
    /// @return The pending requests of the queried nominator
    function nominator_requests(address nominator)
        external
        view
        returns (
            address,
            uint256,
            uint256,
            address[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory
        );

    /// @dev Get the NominatorNominationCount weight hint
    /// Selector: dae5659b
    /// @param nominator The address for which we are querying the nomination count
    /// @return The number of nominations made by the nominator
    function nominator_nomination_count(address nominator)
        external
        view
        returns (uint256);

    /// @dev Temporarily leave the set of validator candidates without unbonding
    /// Selector: 767e0450
    function go_offline() external;

    /// @dev Rejoin the set of validator candidates if previously had called `go_offline`
    /// Selector: d2f73ceb
    function go_online() external;

    /// @dev Join the set of validator candidates
    /// Selector: f98e1021
    /// @param controller The paired controller to the stash account
    /// @param relayer The relayer account for cross-chain functionality (optional)
    /// @param amount The amount self-bonded by the caller to become a validator candidate
    /// @param candidateCount The number of candidates in the CandidatePool
    function join_candidates(
        address controller,
        address relayer,
        uint256 amount,
        uint256 candidateCount
    ) external;

    /// @dev Request to bond more for validator candidates
    /// Selector: c57bd3a8
    /// @param more The additional amount self-bonded
    function candidate_bond_more(uint256 more) external;

    /// @dev Request to leave the set of validator candidates
    /// Selector: 60afbac6
    /// @param candidateCount The number of candidates in the CandidatePool
    function schedule_leave_candidates(uint256 candidateCount) external;

    /// @dev Request to bond less for validator candidates
    /// Selector: 034c47bc
    /// @param less The amount to be subtracted from self-bond and unreserved
    function schedule_candidate_bond_less(uint256 less) external;

    /// @dev Execute due request to leave the set of validator candidates
    /// Selector: e33a8f25
    /// @param candidateNominationCount The number of nominations for the candidate to be revoked
    function execute_leave_candidates(uint256 candidateNominationCount)
        external;

    /// @dev Execute pending candidate bond request
    /// Selector: 6c76b502
    function execute_candidate_bond_less() external;

    /// @dev Cancel request to leave the set of validator candidates
    /// Selector: 0880b3e2
    /// @param candidateCount The number of candidates in the CandidatePool
    function cancel_leave_candidates(uint256 candidateCount) external;

    /// @dev Cancel pending candidate bond request
    /// Selector: 583d0fdc
    function cancel_candidate_bond_less() external;

    /// @dev Set the commission ratio of the given candidate
    /// Selector: 6492d2e0
    function set_validator_commission(uint256 commission) external;

    /// @dev Reset the paired controller account of the requested stash
    /// Selector: 91b10ffa
    /// @param new_controller The new controller to be set
    function set_controller(address new_controller) external;

    /// @dev Set the validator candidate reward destination
    /// Selector: 4b4323fb
    /// @param new_reward_dst The new reward destination to be set (Staked = 0, Account = 1)
    function set_candidate_reward_dst(uint256 new_reward_dst) external;

    /// @dev Make a nomination in support of a validator candidate
    /// Selector: 49df6eb3
    /// @param candidate The address of the supported validator candidate
    /// @param amount The amount bonded in support of the validator candidate
    /// @param candidateNominationCount The number of nominations in support of the candidate
    /// @param nominatorNominationCount The number of existing nominations by the caller
    function nominate(
        address candidate,
        uint256 amount,
        uint256 candidateNominationCount,
        uint256 nominatorNominationCount
    ) external;

    /// @dev Bond more for nominators with respect to a specific validator candidate
    /// Selector: 971d44c8
    /// @param candidate The address of the validator candidate for which nomination shall increase
    /// @param more The amount by which the nomination is increased
    function nominator_bond_more(address candidate, uint256 more) external;

    /// @dev Request to leave the set of nominators
    /// Selector: 13153b19
    function schedule_leave_nominators() external;

    /// @dev Request to revoke an existing nomination
    /// Selector: 5b84b7c7
    /// @param candidate The address of the validator candidate which will no longer be supported
    function schedule_revoke_nomination(address candidate) external;

    /// @dev Request to bond less for nominators with respect to a specific validator candidate
    /// Selector: 774bef4d
    /// @param candidate The address of the validator candidate for which nomination shall decrease
    /// @param less The amount by which the nomination is decreased (upon execution)
    function schedule_nominator_bond_less(address candidate, uint256 less)
        external;

    /// @dev Execute request to leave the set of nominators and revoke all nominations
    /// Selector: 4480de22
    /// @param nominatorNominationCount The number of active nominations to be revoked by nominator
    function execute_leave_nominators(uint256 nominatorNominationCount)
        external;

    /// @dev Execute pending nomination request (if exists && is due)
    /// Selector: bfb13332
    /// @param candidate The address of the candidate
    function execute_nomination_request(address candidate) external;

    /// @dev Cancel request to leave the set of nominators
    /// Selector: e48105f0
    function cancel_leave_nominators() external;

    /// @dev Cancel pending nomination request (already made in support of input by caller)
    /// Selector: bdb20cae
    /// @param candidate The address of the candidate
    function cancel_nomination_request(address candidate) external;

    /// @dev Set the nominator reward destination
    /// Selector: 5706390d
    /// @param new_reward_dst The new reward destination to be set (Staked = 0, Account = 1)
    function set_nominator_reward_dst(uint256 new_reward_dst) external;
}
```


# Governance

The Bifrost Network is a decentralized network managed by BFC holders. At the heart of the Bifrost Network's governance protocol, BFC holders reflect changes to the network by voting on the community's proposed referenda through a stake-weighted voting system based on their stakes.

All actions related to governance can be performed through the following ***Governance*** contract.

## Governance contract

* address: `0x0000000000000000000000000000000000000800`
* Since the Solidity compiler does not support this function, it is recommended to call a method through the interface below.

```solidity
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.0;

/**
 * @title Pallet Governance Interface
 *
 * The interface through which solidity contracts will interact with governance related pallets
 * Address :    0x0000000000000000000000000000000000000800
 */

interface Governance {
    struct ongoing_referendum_info_meta_data {
        uint256 end;
        bytes32 proposal_hash;
        uint256 threshold;
        uint256 delay;
        uint256 ayes;
        uint256 nays;
        uint256 turnout;
    }

    struct finished_referendum_info_meta_data {
        bool approved;
        uint256 end;
    }

    /**
     * Get The total number of public proposals
     * Selector: 56fdf547
     * @return The total number of public proposals
     */
    function public_prop_count() external view returns (uint256);

    /**
     * Get details of the deposit for a proposal.
     * Selector: a30305e9
     * @param prop_index The index of the proposal you are interested in
     * @return (total deposit, initial deposit, depositors)
     */
    function deposit_of(uint256 prop_index)
        external
        view
        returns (
            uint256,
            uint256,
            address[] memory
        );

    /**
     * Get details of the votes for a referendum.
     * Selector: 09daa4d8
     * @param ref_index The index of the referendum you are interested in
     * @return (referenda index, voters, voting powers, voting sides, convictions)
     */
    function voting_of(uint256 ref_index)
        external
        view
        returns (
            uint256,
            address[] memory,
            uint256[] memory,
            bool[] memory,
            uint256[] memory
        );

    /**
     * Get details of the votes for the given account.
     * Selector: 198a1bd9
     * @param account The account address you are interested in
     * @return A tuple including:
     * * The index of voted referendas (removable)
     * * The raw votes submitted for each referenda (conviction not applied)
     * * The voting side of each referenda (true: aye, false: nay)
     * * The conviction multiplier of each votes (0~6)
     * * The delegated amount of votes received for this account (conviction applied)
     * * The delegated raw amount of votes received for this account (conviction not applied)
     * * The block number that expires the locked balance
     * * The balance locked to the network
     */
    function account_votes(address account)
        external
        view
        returns (
            uint256[] memory,
            uint256[] memory,
            bool[] memory,
            uint256[] memory,
            uint256,
            uint256,
            uint256,
            uint256
        );

    /**
     * Get the index of the lowest unbaked referendum
     * Selector: 0388f282
     * @return The lowest referendum index representing an unbaked referendum.
     */
    function lowest_unbaked() external view returns (uint256);

    /**
     * Get the details about an ongoing referendum.
     * Selector: 8b93d11a
     *
     * @dev This, along with `finished_referendum_info`, wraps the pallet's `referendum_info`
     * function. It is necessary to split it into two here because Solidity only has c-style enums.
     * @param ref_index The index of the referendum you are interested in
     * @return A tuple including:
     * * The block when voting on this referendum will end
     * * The proposal hash
     * * The biasing mechanism 0-SuperMajorityApprove, 1-SuperMajorityAgainst, 2-SimpleMajority
     * * The delay between passing and launching
     * * The total aye vote (including conviction)
     * * The total nay vote (including conviction)
     * * The total turnout (not including conviction)
     */
    function ongoing_referendum_info(uint256 ref_index)
        external
        view
        returns (ongoing_referendum_info_meta_data memory);

    /**
     * Get the details about a finished referendum.
     * Selector: b1fd383f
     *
     * @dev This, along with `ongoing_referendum_info`, wraps the pallet's `referendum_info`
     * function. It is necessary to split it into two here because Solidity only has c-style enums.
     * @param ref_index The index of the referendum you are interested in
     * @return A tuple including whether the referendum passed, and the block at which it finished.
     */
    function finished_referendum_info(uint256 ref_index)
        external
        view
        returns (finished_referendum_info_meta_data memory);

    /**
     * Make a new proposal
     * Selector: 7824e7d1
     *
     * @param proposal_hash The hash of the proposal you are making
     * @param value The number of tokens to be locked behind this proposal.
     */
    function propose(bytes32 proposal_hash, uint256 value) external;

    /**
     * Signal agreement (endorsement) with a proposal
     * Selector: c7a76601
     *
     * @dev No amount is necessary here. Seconds are always for the same amount that the original
     * proposer locked. You may second multiple times.
     *
     * @param prop_index index of the proposal you want to second
     * @param seconds_upper_bound A number greater than or equal to the current number of seconds.
     * This is necessary for calculating the weight of the call.
     */
    function second(uint256 prop_index, uint256 seconds_upper_bound) external;

    /**
     * Vote on a referendum.
     * Selector: f56cb3b3
     *
     * @param ref_index index of the referendum you want to vote in
     * @param aye `true` is a vote to enact the proposal; `false` is a vote to keep the status quo.
     * @param vote_amount The number of tokens you are willing to lock if you get your way
     * @param conviction How strongly you want to vote. Higher conviction means longer lock time.
     * This must be an integer in the range 0 to 6
     *
     * @dev This function only supposrts `Standard` votes where you either vote aye or nay.
     * It does not support `Split` votes where you vote on both sides. If such a need
     * arises, we should add an additional function to this interface called `split_vote`.
     */
    function vote(
        uint256 ref_index,
        bool aye,
        uint256 vote_amount,
        uint256 conviction
    ) external;

    /** Remove a vote for a referendum.
     * Selector: 2042f50b
     *
     * @dev Locks get complex when votes are removed. See pallet-democracy's docs for details.
     * @param ref_index The index of the referendum you are interested in
     */
    function remove_vote(uint256 ref_index) external;

    /**
     * Delegate voting power to another account.
     * Selector: 0185921e
     *
     * @dev The balance delegated is locked for as long as it is delegated, and thereafter for the
     * time appropriate for the conviction's lock period.
     * @param target The account to whom the vote shall be delegated.
     * @param conviction The conviction with which you are delegating.
     * This must be an integer in the range 0 to 6
     * @param amount The number of tokens whose voting power shall be delegated.
     */
    function delegate(
        address target,
        uint256 conviction,
        uint256 amount
    ) external;

    /**
     * Undelegate voting power
     * Selector: cb37b8ea
     *
     * @dev Tokens may be unlocked once the lock period corresponding to the conviction with which
     * the delegation was issued has elapsed.
     */
    function undelegate() external;

    /**
     * Unlock tokens that have an expired lock.
     * Selector: 2f6c493c
     *
     * @param target The account whose tokens should be unlocked. This may be any account.
     */
    function unlock(address target) external;

    /**
     * Register the preimage for an upcoming proposal. This doesn't require the proposal to be
     * in the dispatch queue but does require a deposit, returned once enacted.
     * Selector: 200881f5
     *
     * @param encoded_proposal The scale-encoded proposal whose hash has been submitted on-chain.
     */
    function note_preimage(bytes memory encoded_proposal) external;

    /**
     * Register the preimage for an upcoming proposal. This requires the proposal to be
     * in the dispatch queue. No deposit is needed. When this call is successful, i.e.
     * the preimage has not been uploaded before and matches some imminent proposal,
     * no fee is paid.
     * Selector: cf205f96
     *
     * @param encoded_proposal The scale-encoded proposal whose hash has been submitted on-chain.
     */
    function note_imminent_preimage(bytes memory encoded_proposal) external;
}
```


# RelayManager

A *relayer* that is part of a full validator has its own account that is different from the controller address of the validator. Therefore, a function to check the selected relayers in a specific round is separately required.

All actions related to verifying the authority of the *relayer* are performed through the following ***RelayerManager*** contract.

## RelayManager contract

* address: `0x0000000000000000000000000000000000002000`
* Since the Solidity compiler does not support this function, it is recommended to call a method through the interface below.

```solidity
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.0;

/**
 * @title The interface through which solidity contracts will interact with pallet_relay_manager
 * We follow this same interface including four-byte function selectors, in the precompile that
 * wraps the pallet
 * Address :    0x0000000000000000000000000000000000002000
 */

interface RelayManager {
    struct relayer_state_meta_data {
        address relayer;
        address controller;
        uint256 status;
    }

    /// @dev Check whether the specified address is currently a part of the relayer pool
    /// Selector: 976a75f1
    /// @param relayer the address that we want to confirm
    /// @return A boolean confirming whether the address is a part of the relayer pool
    function is_relayer(address relayer) external view returns (bool);

    /// @dev Check whether the specified address is currently or was a part of the active relayer set
    /// Selector: b6f0d1d0
    /// @param relayer the address that we want to confirm
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return A boolean confirming whether the address is a part of the active relayer set
    function is_selected_relayer(address relayer, bool is_initial)
        external
        view
        returns (bool);

    /// @dev Check whether the specified address elements is currently a part of the relayer pool
    /// Selector: 1768adb0
    /// @param relayers the address array that we want to confirm
    /// @return A boolean confirming whether the address array is a part of the relayer pool
    function is_relayers(address[] calldata relayers)
        external
        view
        returns (bool);

    /// @dev Check whether the specified address elements is currently or was a part of the active relayer set
    /// Selector: f6bdf202
    /// @param relayers the address array that we want to confirm
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return A boolean confirming whether the address array is a part of the active relayer set
    function is_selected_relayers(address[] calldata relayers, bool is_initial)
        external
        view
        returns (bool);

    /// @dev Check whether the specified address elements is currently or was identical with the active relayer set
    /// Selector: 17cc85f8
    /// @param relayers the address array that we want to confirm
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return A boolean confirming whether the address array is identical with the active relayer set
    function is_complete_selected_relayers(
        address[] calldata relayers,
        bool is_initial
    ) external view returns (bool);

    /// @dev Check whether the specified address was a part of the given round active set
    /// Selector: f8448c30
    /// @param round_index the round index that we want to confirm
    /// @param relayer the address that we want to confirm is the active set
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return A boolean confirming whether the address was in the active set
    function is_previous_selected_relayer(
        uint256 round_index,
        address relayer,
        bool is_initial
    ) external view returns (bool);

    /// @dev Check whether the specified address array was a part of the given round active set
    /// Selector: 39bae210
    /// @param round_index the round index that we want to confirm
    /// @param relayers the address array that we want to confirm is the active set
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return A boolean confirming whether the address array was in the active set
    function is_previous_selected_relayers(
        uint256 round_index,
        address[] calldata relayers,
        bool is_initial
    ) external view returns (bool);

    /// @dev Check whether the given address sent a heartbeat
    /// Selector: 1ace2613
    /// @return A boolean that represents whether the given address has sent a heartbeat in the current session
    function is_heartbeat_pulsed(address relayer) external view returns (bool);

    /// @dev Get the active relayers of the current round
    /// Selector: dcc7e6e0
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return The list of the active relayers
    function selected_relayers(bool is_initial)
        external
        view
        returns (address[] memory);

    /// @dev Get the previous active relayers of the given round
    /// Selector: 6d709a20
    /// @param round_index the round index that we want to confirm
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return The list of the previous selected relayers
    function previous_selected_relayers(uint256 round_index, bool is_initial)
        external
        view
        returns (address[] memory);

    /// @dev Get the current state of joined relayers
    /// Selector: 6e93ba34
    /// @return The list of the joined relayers (0: relayers, 1: controllers)
    function relayer_pool()
        external
        view
        returns (address[] memory, address[] memory);

    /// @dev Get the active relayer sets majority of the current round
    /// Selector: d2ea63fb
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return The majority of the current round
    function majority(bool is_initial) external view returns (uint256);

    /// @dev Get the active relayer sets majority of the given round
    /// Selector: ea6ce574
    /// @param round_index the round index that we want to confirm
    /// @param is_initial the flag that determines whether to confirm for the current state or at the beginning of the current round
    /// @return The majority of the given round
    function previous_majority(uint256 round_index, bool is_initial)
        external
        view
        returns (uint256);

    /// @dev Get the current rounds index
    /// Selector: 6f31dd98
    /// @return The current rounds index
    function latest_round() external view returns (uint256);

    /// @dev Get the current state of the given relayer
    /// Selector: 3f4e4fae
    /// @return The current state of the given relayer address. (relayer, controller, status)
    function relayer_state(address relayer)
        external
        view
        returns (relayer_state_meta_data memory);

    /// @dev Get the current state of relayers
    /// Selector: a77293f0
    /// @return The current state of relayers registered in the network
    function relayer_states()
        external
        view
        returns (
            address[] memory,
            address[] memory,
            uint256[] memory
        );

    /// @dev Sends a heartbeat that sets relayer unresponsiveness
    /// Selector: 3defb962
    function heartbeat() external;
}
```


# Pallet Interfaces

The Bifrost Network is built by the Substrate framework and has multiple implemented FRAME pallets. The Bifrost Network also has multiple custom pallets for its core functionality. This section outlines the definitions of the implemented custom pallets.


# BfcStaking

### Description

The core DPoS consensus mechanism of the Bifrost Node is defined in `pallet_bfc_staking`. The `pallet_bfc_staking` is a custom pallet that defines the concepts of validators and nominators and also manages their self-bonds and nominations. In addition, it defines the concept of rounds as well as the logic within the rounds.

###

### Extrinsics

**set\_staking\_expectations(expectations: `Range<BalanceOf>`)**

* interface: `api.tx.bfcStaking.setStakingExpectations`
* summary: Sets the expectations for total staked. These expectations determine the issuance of the round. The origin should be the root.

**set\_inflation(schedule: `Range<Perbill>`)**

* interface: `api.tx.bfcStaking.setInflation`
* summary: Sets the annual inflation rate to derive per-round inflation. The origin should be the root.

**set\_max\_full\_selected(new: `u32`)**

* interface: `api.tx.bfcStaking.setMaxFullSelected`
* summary: Sets the maximum number of full validator candidates selected per round. The origin should be the root.

**set\_basic\_full\_selected(new: `u32`)**

* interface: `api.tx.bfcStaking.setMaxBasicSelected`
* summary: Sets the maximum number of basic validator candidates selected per round. The origin should be the root.

**set\_min\_total\_selected(new: `u32`)**

* interface: `api.tx.bfcStaking.setMinTotalSelected`
* summary: Sets the minimum number of validator candidates selected per round. The origin should be the root.

**set\_default\_validator\_commission(new: `Perbill`, tier: `TierType`)**

* interface: `api.tx.bfcStaking.setDefaultValidatorCommission`
* summary: Sets the default commission rate for all validators of the given tier. The origin should be the root.

**set\_max\_validator\_commission(new: `Perbill`, tier: `TierType`)**

* interface: `api.tx.bfcStaking.setMaxValidatorCommission`
* summary: Sets the maximum commission rate for all validators of the given tier. The origin should be the root.

**set\_validator\_commission(new: `Perbill`)**

* interface: `api.tx.bfcStaking.setValidatorCommission`
* summary: Sets the commission rate of the given validator. The origin should be the controller account.

**set\_validator\_tier(more: `BalanceOf`, new: `TierType`, relayer?: `AccountId`)**

* interface: `api.tx.bfcStaking.setValidatorTier`
* summary: Modifies validator candidate tier. The actual state reflection will apply at the next round. The origin should be the stash account.

**set\_blocks\_per\_round(new: `u32`)**

* interface: `api.tx.bfcStaking.setBlocksPerRound`
* summary: Sets blocks per round. The `new` round length will be updated immediately in the next block. This also updates the per-round inflation config. The origin should be the root.

**set\_storage\_cache\_lifetime(new: `u32`)**

* interface: `api.tx.bfcStaking.setStorageCacheLifetime`
* summary: Sets the `StorageCacheLifetime` round length. The origin should be the root.

**join\_candidates(controller: `AccountId`, relayer?: `AccountId`, bond: `BalanceOf`, candidate\_count: `u32`)**

* interface: `api.tx.bfcStaking.joinCandidates`
* summary: Join the set of validator candidates. The origin should be the stash account.

**schedule\_leave\_candidates(candidate\_count: `u32`)**

* interface: `api.tx.bfcStaking.scheduleLeaveCandidates`
* summary: Requests to leave the set of candidates. If successful, the account is immediately removed from the candidate pool to prevent selection as a validator. The origin should be the controller account.

**execute\_leave\_candidates(candidate\_nomination\_count: `u32`)**

* interface: `api.tx.bfcStaking.executeLeaveCandidates`
* summary: Executes leave candidates request. The origin should be the stash account.

**cancel\_leave\_candidates(candidate\_count: `u32`)**

* interface: `api.tx.bfcStaking.cancelLeaveCandidates`
* summary: Cancels open request to leave candidates. The origin should be the controller account.

**set\_controller(new: `AccountId`)**

* interface: `api.tx.bfcStaking.setController`
* summary: (Re-)sets the bonded controller account. The origin must be the bonded stash account. The actual change will apply on the next round update. The origin should be the stash account.

**set\_candidate\_reward\_dst(new\_reward\_dst: `RewardDestination`)**

* interface: `api.tx.bfcStaking.setCandidateRewardDst`
* summary: Sets the validator candidate reward destination. The origin should be the controller account.

**set\_nominator\_reward\_dst(new\_reward\_dst: `RewardDestination`)**

* interface: `api.tx.bfcStaking.setNominatorRewardDst`
* summary: Sets the nominator reward destination.

**go\_offline()**

* interface: `api.tx.bfcStaking.goOffline`
* summary: Temporarily leaves the set of validator candidates without unbonding. The origin should be the controller account.

**go\_online()**

* interface: `api.tx.bfcStaking.goOnline`
* summary: Rejoins the set of validator candidates if previously been kicked out or went offline. The origin should be the controller account.

**candidate\_bond\_more(more: `BalanceOf`)**

* interface: `api.tx.bfcStaking.candidateBondMore`
* summary: Increases validator candidate self-bond by `more`. The origin should be the stash account.

**schedule\_candidate\_bond\_less(less: `BalanceOf`)**

* interface: `api.tx.bfcStaking.scheduleCandidateBondLess`
* summary: Requests by validator candidate to decrease self-bond by `less`. The origin should be the controller account.

**execute\_candidate\_bond\_less()**

* interface: `api.tx.bfcStaking.executeCandidateBondLess`
* summary: Executes pending request to adjust the validator candidate self-bond. The origin should be the stash account.

**cancel\_candidate\_bond\_less()**

* interface: `api.tx.bfcStaking.cancelCandidateBondLess`
* summary: Cancels pending request to adjust the validator candidate self bond. The origin should be the controller account.

**nominate(candidate: `AccountId`, amount: `BalanceOf`, candidate\_nomination\_count: `u32`, nomination\_count: `u32`)**

* interface: `api.tx.bfcStaking.nominate`
* summary: Nominates the given `candidate`.

**schedule\_leave\_nominators()**

* interface: `api.tx.bfcStaking.scheduleLeaveNominators`
* summary: Requests to leave the set of nominators.

**execute\_leave\_nominators(nomination\_count: `u32`)**

* interface: `api.tx.bfcStaking.executeLeaveNominators`
* summary: Executes the right to exit the set of nominators and revoke all ongoing nominations.

**cancel\_leave\_nominators()**

* interface: `api.tx.bfcStaking.cancelLeaveNominators`
* summary: Cancels a pending request to exit the set of nominators.

**schedule\_revoke\_nomination(validator: `AccountId`)**

* interface: `api.tx.bfcStaking.scheduleRevokeNomination`
* summary: Requests to revoke an existing nomination.

**nominator\_bond\_more(candidate: `AccountId`, more: `BalanceOf`)**

* interface: `api.tx.bfcStaking.nominatorBondMore`
* summary: Bonds more for a specific validator candidate.

**schedule\_nominator\_bond\_less(candidate: `AccountId`, less: `BalanceOf`)**

* interface: `api.tx.bfcStaking.scheduleNominatorBondLess`
* summary: Requests bond less for a specific validator candidate.

**execute\_nomination\_request(candidate: `AccountId`)**

* interface: `api.tx.bfcStaking.executeNominationRequest`
* summary: Executes pending request to change an existing nomination.

**cancel\_nomination\_request(candidate: `AccountId`)**

* interface: `api.tx.bfcStaking.cancelNominationRequest`
* summary: Cancels request to change an existing nomination.

###

### Storage Values

**Session(): `SessionIndex`**

* interface: `api.query.bfcStaking.session`
* summary: Current session index of current round.

**Round(): `RoundInfo<T::BlockNumber>`**

* interface: `api.query.bfcStaking.round`
* summary: Current round index and specific information.

**StorageCacheLifetime(): `u32`**

* interface: `api.query.bfcStaking.storageCacheLifetime`
* summary: The maximum storage lifetime for storage data to be cached.

**DefaultFullValidatorCommission(): `Perbill`**

* interface: `api.query.bfcStaking.defaultFullValidatorCommission`
* summary: Default commission rate for full validators.

**DefaultBasicValidatorCommission(): `Perbill`**

* interface: `api.query.bfcStaking.defaultBasicValidatorCommission`
* summary: Default commission rate for basic validators.

**MaxFullValidatorCommission(): `Perbill`**

* interface: `api.query.bfcStaking.maxFullValidatorCommission`
* summary: Maximum commission rate for full validators.

**MaxBasicValidatorCommission(): `Perbill`**

* interface: `api.query.bfcStaking.maxBasicValidatorCommission`
* summary: Maximum commission rate for basic validators.

**MaxTotalSelected(): `u32`**

* interface: `api.query.bfcStaking.maxTotalSelected`
* summary: Maximum node candidates selected every round.

**MaxFullSelected(): `u32`**

* interface: `api.query.bfcStaking.maxFullSelected`
* summary: Maximum full node candidates selected every round.

**MaxBasicSelected(): `u32`**

* interface: `api.query.bfcStaking.maxBasicSelected`
* summary: Maximum basic node candidates selected every round.

**MinTotalSelected(): `u32`**

* interface: `api.query.bfcStaking.minTotalSelected`
* summary: Minimum candidates selected every round.

**ProductivityPerBlock(): `Perbill`**

* interface: `api.query.bfcStaking.productivityPerBlock`
* summary: Productivity rate per block in the current round.

**NominatorState(`AccountId`): `Option<Nominator<AccountId, BalanceOf>>`**

* interface: `api.query.bfcStaking.nominatorState`
* summary: Gets nominator state associated with an account if the account is nominating else None.

**CandidateInfo(`AccountId`): `Option<CandidateMetadata<AccountId, BalanceOf, BlockNumberOf>>`**

* interface: `api.query.bfcStaking.candidateInfo`
* summary: Gets validator candidate info associated with an account if the account is candidate else None.

**BondedStash(`AccountId`): `Option<AccountId>`**

* interface: `api.query.bfcStaking.bondedStash`
* summary: Map from all locked "stash" accounts to the controller account.

**TopNominations(`AccountId`): `Option<Nominations<AccountId, BalanceOf>>`**

* interface: `api.query.bfcStaking.topNominations`
* summary: Top nominations for validator candidate.

**BottomNominations(`AccountId`): `Option<Nominations<AccountId, BalanceOf>>`**

* interface: `api.query.bfcStaking.bottomNominations`
* summary: Bottom nominations for validator candidate.

**SelectedCandidates(): `Vec<AccountId>`**

* interface: `api.query.bfcStaking.selectedCandidates`
* summary: Active validator set (full and basic) selected for the current round.

**SelectedFullCandidates(): `Vec<AccountId>`**

* interface: `api.query.bfcStaking.selectedFullCandidates`
* summary: Active full validator set selected for the current round.

**SelectedBasicCandidates(): `Vec<AccountId>`**

* interface: `api.query.bfcStaking.selectedBasicCandidates`
* summary: Active basic validator set selected for the current round.

**CachedSelectedCandidates(): `Vec<(RoundIndex, Vec<AccountId>)>`**

* interface: `api.query.bfcStaking.cachedSelectedCandidates`
* summary: Cached active validator set selected from previous rounds.

**Majority(): `u32`**

* interface: `api.query.bfcStaking.majority`
* summary: Majority of the current active validator set.

**CachedMajority(): `Vec<(RoundIndex, u32)>`**

* interface: `api.query.bfcStaking.cachedMajority`
* summary: Cached majority based on the active validator set selected from previous rounds.

**Total(): `BalanceOf`**

* interface: `api.query.bfcStaking.total`
* summary: Total capital locked by this staking pallet.

**CandidatePool(): `Vec<Bond<AccountId, BalanceOf>>`**

* interface: `api.query.bfcStaking.candidatePool`
* summary: The pool of validator candidates, each with their total voting power.

**AtStake(`RoundIndex`): `ValidatorSnapshot<AccountId, BalanceOf>`**

* interface: `api.query.bfcStaking.atStake`
* summary: Snapshot of validator nomination stake at the start of the round.

**TotalAtStake(`RoundIndex`): `Option<TotalSnapshot<BalanceOf>>`**

* interface: `api.query.bfcStaking.totalAtStake`
* summary: Snapshot of the network state at the start of the round.

**DelayedPayouts(`RoundIndex`): `Option<DelayedPayout<BalanceOf>>`**

* interface: `api.query.bfcStaking.delayedPayouts`
* summary: Delayed reward payouts.

**DelayedControllerSets(`RoundIndex`): `Vec<DelayedControllerSet<AccountId>>`**

* interface: `api.query.bfcStaking.delayedControllerSets`
* summary: Delayed new controller account set requests.

**Staked(`RoundIndex`): `BalanceOf`**

* interface: `api.query.bfcStaking.staked`
* summary: Total counted stake for selected candidates in the round.

**InflationConfig(): `InflationInfo<BalanceOf>`**

* interface: `api.query.bfcStaking.inflationConfig`
* summary: Inflation configuration.

**Points(`RoundIndex`): `RewardPoint`**

* interface: `api.query.bfcStaking.points`
* summary: Total points awarded to validators for block production in the round.

**AwardedPts(`AccountId`): `RewardPoint`**

* interface: `api.query.bfcStaking.awardedPts`
* summary: Points for each validator per round.

**AwardedTokens(): `BalanceOf`**

* interface: `api.query.bfcStaking.awardedTokens`
* summary: Tokens awarded to validators and nominators since genesis.

###

### Constants

**DefaultBlocksPerSession: `u32`**

* interface: `api.consts.bfcStaking.defaultBlocksPerSession`
* summary: Default number of blocks per session at genesis.

**DefaultBlocksPerRound: `u32`**

* interface: `api.consts.bfcStaking.defaultBlocksPerRound`
* summary: Default number of blocks per round at genesis.

**MinBlocksPerRound: `u32`**

* interface: `api.consts.bfcStaking.minBlocksPerRound`
* summary: Default minimum number of blocks per round at genesis.

**StorageCacheLifetimeInRounds: `u32`**

* interface: `api.consts.bfcStaking.storageCacheLifetimeInRounds`
* summary: Maximum lifetime in rounds for certain storage data to be cached.

**LeaveCandidatesDelay: `RoundIndex`**

* interface: `api.consts.bfcStaking.leaveCandidatesDelay`
* summary: Number of rounds that candidates remain bonded before exit request is executable.

**CandidateBondLessDelay: `RoundIndex`**

* interface: `api.consts.bfcStaking.candidateBondLessDelay`
* summary: Number of rounds candidate requests to decrease self-bond must wait to be executable.

**LeaveNominatorsDelay: `RoundIndex`**

* interface: `api.consts.bfcStaking.leaveNominatorsDelay`
* summary: Number of rounds that nominators remain bonded before exit request is executable.

**RevokeNominationDelay: `RoundIndex`**

* interface: `api.consts.bfcStaking.revokeNominationDelay`
* summary: Number of rounds that nominations remain bonded before revocation request is executable.

**NominationBondLessDelay: `RoundIndex`**

* interface: `api.consts.bfcStaking.nominationBondLessDelay`
* summary: Number of rounds that nomination less requests must wait before executable.

**RewardPaymentDelay: `RoundIndex`**

* interface: `api.consts.bfcStaking.rewardPaymentDelay`
* summary: Number of rounds after which block authors are rewarded.

**DefaultMaxSelectedFullCandidates: `u32`**

* interface: `api.consts.bfcStaking.defaultMaxSelectedFullCandidates`
* summary: Default maximum number of selected full node candidates every round.

**DefaultMaxSelectedBasicCandidates: `u32`**

* interface: `api.consts.bfcStaking.defaultMaxSelectedBasicCandidates`
* summary: Default maximum number of selected basic node candidates every round.

**DefaultMinSelectedCandidates: `u32`**

* interface: `api.consts.bfcStaking.defaultMinSelectedCandidates`
* summary: Default minimum number of selected candidates (full and basic) every round.

**MaxTopNominationsPerCandidate: `u32`**

* interface: `api.consts.bfcStaking.maxTopNominationsPerCandidate`
* summary: Maximum top nominations counted per candidate.

**MaxBottomNominationsPerCandidate: `u32`**

* interface: `api.consts.bfcStaking.maxBottomNominationsPerCandidate`
* summary: Maximum bottom nominations counted per candidate.

**MaxNominationsPerNominator: `u32`**

* interface: `api.consts.bfcStaking.maxNominationsPerNominator`
* summary: Maximum nominations per nominator.

**DefaultFullValidatorCommission: `Perbill`**

* interface: `api.consts.bfcStaking.defaultFullValidatorCommission`
* summary: Default commission rate for a full validator.

**DefaultBasicValidatorCommission: `Perbill`**

* interface: `api.consts.bfcStaking.defaultBasicValidatorCommission`
* summary: Default commission rate for a basic validator.

**MaxFullValidatorCommission: `Perbill`**

* interface: `api.consts.bfcStaking.maxFullValidatorCommission`
* summary: Maximum commission rate available for a full validator.

**MaxBasicValidatorCommission: `Perbill`**

* interface: `api.consts.bfcStaking.maxBasicValidatorCommission`
* summary: Maximum commission rate available for a basic validator.

**MinFullValidatorStk: `BalanceOf`**

* interface: `api.consts.bfcStaking.minFullValidatorStk`
* summary: Minimum stake required for any full node candidate to be in `SelectedCandidates` for the round.

**MinBasicValidatorStk: `BalanceOf`**

* interface: `api.consts.bfcStaking.minBasicValidatorStk`
* summary: Minimum stake required for any basic node candidate to be in `SelectedCandidates` for the round.

**MinFullCandidateStk: `BalanceOf`**

* interface: `api.consts.bfcStaking.minFullCandidateStk`
* summary: Minimum stake required for any account to be a full validator candidate.

**MinBasicCandidateStk: `BalanceOf`**

* interface: `api.consts.bfcStaking.minBasicCandidateStk`
* summary: Minimum stake required for any account to be a basic validator candidate.

**MinNominatorStk: `BalanceOf`**

* interface: `api.consts.bfcStaking.minNominatorStk`
* summary: Minimum stake for any registered on-chain account to be a nominator.


# BfcUtility

### Description

This pallet allows users to submit proposals to the community.

### Extrinsics

**community\_proposal(proposal: `Vec<u8>`)**

* interface: `api.tx.bfcUtility.communityProposal`
* summary: General community proposal without changes on codes.

### Storage Values

**AcceptedProposals(): `Vec<Proposal>`**

* interface: `api.query.bfcUtility.acceptedProposals`
* summary: Storage for accepted proposals. Proposal passed by governance will be stored here.

**ProposalIndex(): `PropIndex`**

* interface: `api.query.bfcUtility.proposalIndex`
* summary: Storage for proposal index. Whenever proposal is accepted, index will be increased.


# BfcOffences

### Description

The Bifrost Node tracks offences of validators and penalizes them to maintain network stability. The related implementation is defined in the `pallet_bfc_offences` module which is a central module implemented to handle offences reported through multiple modules and is responsible for counting offences and processing validator slashing.

### Extrinsics

**set\_offence\_expiration(new: `SessionIndex`)**

* interface: `api.tx.bfcOffences.setOffenceExpiration`
* summary: Sets a new offence expiration for all validators. It must be specified in sessions. The origin should be the root.

**set\_max\_offence\_count(new: `OffenceCount`)**

* interface: `api.tx.bfcOffences.setMaxOffenceCount`
* summary: Sets a new maximum offence count for all validators. The origin should be the root.

**set\_offence\_activation(is\_active: `bool`)**

* interface: `api.tx.bfcOffences.setOffenceActivation`
* summary: Sets the activation of validator offence management. The origin should be the root.

**set\_slash\_activation(is\_active: `bool`)**

* interface: `api.tx.bfcOffences.setOffenceActivation`
* summary: Sets the activation of validator slashing. The origin should be the root.

### Storage Values

**ValidatorOffences(`AccountId`): `Option<ValidatorOffenceInfo<BalanceOf>>`**

* interface: `api.query.bfcOffences.validatorOffences`
* summary: The current offence state of a specific validator.

**OffenceExpirationInSessions(): `SessionIndex`**

* interface: `api.query.bfcOffences.offenceExpirationInSessions`
* summary: The current offence expiration in sessions.

**MaximumOffenceCount(): `OffenceCount`**

* interface: `api.query.bfcOffences.maximumOffenceCount`
* summary: The current maximum offence count for all validators.

**IsOffenceActive(): `bool`**

* interface: `api.query.bfcOffences.isOffenceActive`
* summary: The current activation of validator offence management.

**IsSlashActive(): `bool`**

* interface: `api.query.bfcOffences.isSlashActive`
* summary: The current activation of validator slashing.

###

### Constants

**DefaultOffenceExpirationInSessions: `SessionIndex`**

* interface: `api.consts.bfcOffences.defaultOffenceExpirationInSessions`
* summary: The default offence expiration in sessions.

**DefaultMaximumOffenceCount: `OffenceCount`**

* interface: `api.consts.bfcOffences.defaultMaximumOffenceCount`
* summary: The default maximum offence count for all validators.

**IsOffenceActive: `bool`**

* interface: `api.consts.bfcOffences.isOffenceActive`
* summary: The activation of validator offence management.

**IsSlashActive: `bool`**

* interface: `api.consts.bfcOffences.isSlashActive`
* summary: The activation of validator slashing.


# RelayManager

### Description

Full node operators on the Bifrost Network must additionally operate the relayer program. Therefore, carefully managing and tracking the state of all relayers is crucial to maintaining the stability of the network. The core implementation for relayer management is defined in `pallet_relay_manager`.

###

### Extrinsics

**set\_storage\_cache\_lifetime(new: `u32`)**

* interface: `api.tx.relayManager.setStorageCacheLifetime`
* summary: Sets the `StorageCacheLifetime` round length. The origin should be the root.

**set\_heartbeat\_offence\_activation(is\_active: `bool`)**

* interface: `api.tx.relayManager.setHeartbeatOffenceActivation`
* summary: Sets the activation of relayer heartbeat management. The origin should be the root.

**set\_heartbeat\_slash\_fraction(new: `Perbill`)**

* interface: `api.tx.relayManager.setHeartbeatSlashFraction`
* summary: Sets a new slash fraction for heartbeat offences. The origin should be the root.

**set\_relayer(new: `AccountId`)**

* interface: `api.tx.relayManager.setRelayer`
* summary: (Re-)sets the bonded relayer account. The origin must be the bonded controller account. The state reflection will be immediately applied.

**heartbeat()**

* interface: `api.tx.relayManager.heartbeat`
* summary: Sends a new heartbeat to manage relayer liveness for the current session. The origin must be the registered relayer account, and only the selected relayers can request.

###

### Storage Values

**StorageCacheLifetime(): `u32`**

* interface: `api.query.relayManager.storageCacheLifetime`
* summary: The maximum storage lifetime for storage data to be cached.

**Round(): `RoundIndex`**

* interface: `api.query.relayManager.round`
* summary: The current round index.

**BondedController(`AccountId`): `Option<AccountId>`**

* interface: `api.query.relayManager.bondedController`
* summary: Mapped controller accounts to the relayer account.

**RelayerPool(): `Vec<Relayer<AccountId>>`**

* interface: `api.query.relayManager.relayerPool`
* summary: The pool of relayers of the current round (including selected and non-selected relayers).

**RelayerState(): `Option<RelayerMetadata<AccountId>>`**

* interface: `api.query.relayManager.relayerState`
* summary: The current state of a specific relayer.

**SelectedRelayers(): `Vec<AccountId>`**

* interface: `api.query.relayManager.selectedRelayers`
* summary: The active relayer set selected for the current round.

**InitialSelectedRelayers(): `Vec<AccountId>`**

* interface: `api.query.relayManager.initialSelectedRelayers`
* summary: The active relayer set selected at the beginning of the current round.

**CachedSelectedRelayers(): `Vec<(RoundIndex, Vec<AccountId>)>`**

* interface: `api.query.relayManager.cachedSelectedRelayers`
* summary: The cached active relayer set selected from previous rounds.

**CachedInitialSelectedRelayers(): `Vec<(RoundIndex, Vec<AccountId>)>`**

* interface: `api.query.relayManager.cachedInitialSelectedRelayers`
* summary: The cached active relayer set selected from the beginning of each previous round.

**Majority(): `u32`**

* interface: `api.query.relayManager.majority`
* summary: The majority of the current active relayer set.

**InitialMajority(): `u32`**

* interface: `api.query.relayManager.initialMajority`
* summary: The majority of the current active relayer set at the beginning of the current round.

**CachedMajority(): `Vec<(RoundIndex, u32)>`**

* interface: `api.query.relayManager.cachedMajority`
* summary: The cached majority based on the active relayer set selected from previous rounds.

**CachedInitialMajority(): `Vec<(RoundIndex, u32)>`**

* interface: `api.query.relayManager.cachedInitialMajority`
* summary: The cached majority based on the active relayer set selected from the beginning of each previous rounds.

**ReceivedHeartbeats(`AccountId`): `bool`**

* interface: `api.query.relayManager.receivedHeartbeats`
* summary: The received heartbeats of a specific relayer in the current session.

**IsHeartbeatOffenceActive(): `bool`**

* interface: `api.query.relayManager.isHeartbeatOffenceActive`
* summary: The activation of relayer heartbeat offence management.

**HeartbeatSlashFraction(): `Perbill`**

* interface: `api.query.relayManager.heartbeatSlashFraction`
* summary: The slash fraction for heartbeat offences.

###

### Constants

**StorageCacheLifetimeInRounds: `u32`**

* interface: `api.consts.relayManager.storageCacheLifetimeInRounds`
* summary: The maximum lifetime in rounds for storage data to be cached.

**IsHeartbeatOffenceActive: `bool`**

* interface: `api.consts.relayManager.isHeartbeatOffenceActive`
* summary: The activation of relayer heartbeat offence management.

**DefaultHeartbeatSlashFraction: `Perbill`**

* interface: `api.consts.relayManager.defaultHeartbeatSlashFraction`
* summary: The default slash fraction for heartbeat offences.


# Client API

The following sections contain the supported API endpoints of the Bifrost Network and the Bifrost Explorer.


# JSON-RPC API

The following sections contain known RPC methods available on the Bifrost Network which allow you to interact with the actual node, query, and submit.

## Testnet (ChainId: 49088)

|                Public Endpoints (rpc/ws)                |
| :-----------------------------------------------------: |
|    <https://public-01.testnet.bifrostnetwork.com/rpc>   |
|    <https://public-02.testnet.bifrostnetwork.com/rpc>   |
| <https://bifrost-testnet.g.allthatnode.com/archive/evm> |
|  \*<https://bifrost-testnet.g.allthatnode.com/full/evm> |
|     wss\://public-01.testnet.bifrostnetwork.com/wss     |
|     wss\://public-02.testnet.bifrostnetwork.com/wss     |
|   wss\://bifrost-testnet.g.allthatnode.com/archive/evm  |
|   \*wss\://bifrost-testnet.g.allthatnode.com/full/evm   |

{% hint style="info" %}
"\*" denotes a full node RPC.
{% endhint %}

## Mainnet (ChainId: 3068)

|                Public Endpoints (rpc/ws)                |
| :-----------------------------------------------------: |
|    <https://public-01.mainnet.bifrostnetwork.com/rpc>   |
|    <https://public-02.mainnet.bifrostnetwork.com/rpc>   |
| <https://bifrost-mainnet.g.allthatnode.com/archive/evm> |
|  \*<https://bifrost-mainnet.g.allthatnode.com/full/evm> |
|     wss\://public-01.mainnet.bifrostnetwork.com/wss     |
|     wss\://public-02.mainnet.bifrostnetwork.com/wss     |
|   wss\://bifrost-mainnet.g.allthatnode.com/archive/evm  |
|   \*wss\://bifrost-mainnet.g.allthatnode.com/full/evm   |


# author

### hasKey(**publicKey: `Bytes`, keyType: `Text`): `bool`**

* **interface**: `api.rpc.author.hasKey`
* **jsonrpc**: `author_hasKey`
* **summary**: Returns true if the keystore has private keys for the given public key and key type.

### **hasSessionKeys(sessionKeys: `Bytes`): `bool`**

* **interface**: `api.rpc.author.hasSessionKeys`
* **jsonrpc**: `author_hasSessionKeys`
* **summary**: Returns true if the keystore has private keys for the given session public keys.

### **insertKey(keyType: `Text`, suri: `Text`, publicKey: `Bytes`): `Bytes`**

* **interface**: `api.rpc.author.insertKey`
* **jsonrpc**: `author_insertKey`
* **summary**: Inserts a key into the keystore.

### **pendingExtrinsics(): `Vec<Extrinsic>`**

* **interface**: `api.rpc.author.pendingExtrinsics`
* **jsonrpc**: `author_pendingExtrinsics`
* **summary**: Returns all pending extrinsics, potentially grouped by sender

### **removeExtrinsic(bytesOrHash: `Vec<ExtrinsicOrHash>`): `Vec<Hash>`**

* **interface**: `api.rpc.author.removeExtrinsic`
* **jsonrpc**: `author_removeExtrinsic`
* **summary**: Removes given extrinsic from the pool and temporarily ban it to prevent reimporting

### **rotateKeys(): `Bytes`**

* **interface**: `api.rpc.author.rotateKeys`
* **jsonrpc**: `author_rotateKeys`
* **summary**: Generates new session keys and returns the corresponding public keys

### **submitExtrinsic(extrinsic: `Extrinsic`): `Hash`**

* **interface**: `api.rpc.author.submitExtrinsic`
* **jsonrpc**: `author_submitExtrinsic`
* **summary**: Submits a fully formatted extrinsic for block inclusion


# chain

###

### **getBlock(hash?: `BlockHash`): `SignedBlock`**

* **interface**: `api.rpc.chain.getBlock`
* **jsonrpc**: `chain_getBlock`
* **summary**: Gets the header and body of the target chain block

### **getBlockHash(blockNumber?: `BlockNumber`): `BlockHash`**

* **interface**: `api.rpc.chain.getBlockHash`
* **jsonrpc**: `chain_getBlockHash` (alias=`chain_getHead`)
* **summary**: Gets the block hash for a specific block

### **getFinalizedHead(): `BlockHash`**

* **interface**: `api.rpc.chain.getFinalizedHead`
* **jsonrpc**: `chain_getFinalizedHead` (alias=`chain_getFinalisedHead`)
* **summary**: Gets hash of the last finalized block in the canon chain

### **getHeader(hash?: `BlockHash`): `Header`**

* **interface**: `api.rpc.chain.getHeader`
* **jsonrpc**: `chain_getHeader`
* **summary**: Retrieves the header for a specific block

### **subscribeAllHeads(): `Header`**

* **interface**: `api.rpc.chain.subscribeAllHeads`
* **jsonrpc**: `chain_subscribeAllHeads`
* **summary**: Retrieves the newest header via subscription

### **subscribeFinalizedHeads(): `Header`**

* **interface**: `api.rpc.chain.subscribeFinalizedHeads`
* **jsonrpc**: `chain_subscribeFinalizedHeads` (alias=`chain_subscribeFinalisedHeads`)
* **summary**: Retrieves the best finalized header via subscription.

### **subscribeNewHeads(): `Header`**

* **interface**: `api.rpc.chain.subscribeNewHeads`
* **jsonrpc**: `chain_subscribeNewHeads` (alias=`chain_subscribeNewHead`)
* **summary**: Retrieves the best header via subscription.


# childstate

###

### **getKeys(childKey: `PrefixedStorageKey`, prefix: `StorageKey`, at?: `Hash`): `Vec<StorageKey>`**

* **interface**: `api.rpc.childstate.getKeys`
* **jsonrpc**: `childstate_getKeys`
* **summary**: Returns the keys with prefix from a child storage, leave empty to get all the keys

### **getKeysPaged(childKey: `PrefixedStorageKey`, prefix: `StorageKey`, count: `u32`, startKey?: `StorageKey`, at?: `Hash`): `Vec<StorageKey>`**

* **interface**: `api.rpc.childstate.getKeysPaged`
* **jsonrpc**: `childstate_getKeysPaged`
* **summary**: Returns the keys with prefix from a child storage with pagination support

### **getStorage(childKey: `PrefixedStorageKey`, key: `StorageKey`, at?: `Hash`): `Option<StorageData>`**

* **interface**: `api.rpc.childstate.getStorage`
* **jsonrpc**: `childstate_getStorage`
* **summary**: Returns a child storage entry at a specific block state

### **getStorageEntries(childKey: `PrefixedStorageKey`, keys: `Vec<StorageKey>`, at?: `Hash`): `Vec<Option<StorageData>>`**

* **interface**: `api.rpc.childstate.getStorageEntries`
* **jsonrpc**: `childstate_getStorageEntries`
* **summary**: Returns child storage entries for multiple keys at a specific block state

### **getStorageHash(childKey: `PrefixedStorageKey`, key: `StorageKey`, at?: `Hash`): `Option<Hash>`**

* **interface**: `api.rpc.childstate.getStorageHash`
* **jsonrpc**: `childstate_getStorageHash`
* **summary**: Returns the hash of a child storage entry at a block state

### **getStorageSize(childKey: `PrefixedStorageKey`, key: `StorageKey`, at?: `Hash`): `Option<u64>`**

* **interface**: `api.rpc.childstate.getStorageSize`
* **jsonrpc**: `childstate_getStorageSize`
* **summary**: Returns the size of a child storage entry at a block state


# debug

### **traceBlockByHash(id: `BlockHash`, params?: `TraceParams`): `Vec<TransactionTrace>`**

* **jsonrpc**: `debug_traceBlockByHash`
* **summary**: `traceBlockByHash` accepts a block hash and will replay the block that is already present in the database. For the second parameter, see the`TraceParams` reference.

### **traceBlockByNumber(id: `BlockNumber`, params?: `TraceParams`): `Vec<TransactionTrace>`**

* **jsonrpc**: `debug_traceBlockByNumber`
* **summary**: `traceBlockByNumber` accepts a block number and will replay the block that is already present in the database. For the second parameter, see the`TraceParams` reference.

### **traceTransaction(transaction\_hash: `hash`, params?: `TraceParams`): `TransactionTrace`**

* **jsonrpc**: `debug_traceTransaction`
* **summary**: The `traceTransaction`debugging method will attempt to run the transaction in the exact same manner as it was executed on the network. It will replay any transaction that may have been executed prior to the current one before it finally attempts to execute the transaction that corresponds to the given hash. For the second parameter, see the `TraceParams` reference.


# eth

###

### **accounts(): `Vec<H160>`**

* **interface**: `api.rpc.eth.accounts`
* **jsonrpc**: `eth_accounts`
* **summary**: Returns a list of addresses owned by client.

### **blockNumber(): `U256`**

* **interface**: `api.rpc.eth.blockNumber`
* **jsonrpc**: `eth_blockNumber`
* **summary**: Returns the current "latest" block number.

### **call(transaction: `transactionObject`, block?: `BlockNumber`): `HexString`**

* **interface**: `api.rpc.eth.call`
* **jsonrpc**: `eth_call`
* **summary**: Executes a new message call immediately without creating a transaction on the block chain.

**chainId(): `HexString`**

* **interface**: `api.rpc.eth.chainId`
* **jsonrpc**: `eth_chainId`
* **summary**: Returns the currently configured chain id.

### **coinbase(): `H160`**

* **interface**: `api.rpc.eth.coinbase`
* **jsonrpc**: `eth_coinbase`
* **summary**: Returns block author.

### **estimateGas(transaction: `transactionObject`, block?: `BlockNumber`): `HexString`**

* **interface**: `api.rpc.eth.estimateGas`
* **jsonrpc**: `eth_estimateGas`
* **summary**: Estimates gas needed for execution of given transaction.

### **feeHistory(blockCount: `U256`, newest\_block: `BlockNumber`, reward\_percentiles?: `Vec<f64>`): `FeeHistory`**

* **interface**: `api.rpc.eth.feeHistory`
* **jsonrpc**: `eth_feeHistory`
* **summary**: Introduced in EIP-1159 for getting information on the appropriate priority fee to use.

### **gasPrice(): `HexString`**

* **interface**: `api.rpc.eth.gasPrice`
* **jsonrpc**: `eth_gasPrice`
* **summary**: Returns the current gas price in wei.

### **getBalance(address: `H160`, block?: `BlockNumber`): `HexString`**

* **interface**: `api.rpc.eth.getBalance`
* **jsonrpc**: `eth_getBalance`
* **summary**: Returns the balance of the account of given address.

### **getBlockByHash(hash: `H256`, full?: `bool`): `BlockObject`**

* **interface**: `api.rpc.eth.getBlockByHash`
* **jsonrpc**: `eth_getBlockByHash`
* **summary**: Returns information about a block by hash.

### **getBlockByNumber(BlockNumber: `BlockNumber`, full?: `bool`): `BlockObject`**

* **interface**: `api.rpc.eth.getBlockByNumber`
* **jsonrpc**: `eth_getBlockByNumber`
* **summary**: Returns information about a block by hash.

### **getBlockTransactionCountByHash(hash: `H256`): `U256`**

* **interface**: `api.rpc.eth.getBlockTransactionCountByHash`
* **jsonrpc**: `eth_getBlockTransactionCountByHash`
* **summary**: Returns the number of transactions in the block with the given block hash.

### **getBlockTransactionCountByNumber(BlockNumber: `BlockNumber`): `U256`**

* **interface**: `api.rpc.eth.getBlockTransactionCountByNumber`
* **jsonrpc**: `eth_getBlockTransactionCountByNumber`
* **summary**: Returns the number of transactions in the block with the given block number.

### **getCode(address: `H160`, number?: `BlockNumber`): `Bytes`**

* **interface**: `api.rpc.eth.getCode`
* **jsonrpc**: `eth_getCode`
* **summary**: Returns the compiled smart contract code, if any, at a given address.

### **getFilterChanges(index: `Index`): `FilterChanges`**

* **interface**: `api.rpc.eth.getFilterChanges`
* **jsonrpc**: `eth_getFilterChanges`
* **summary**: Polling method for a filter, which returns an array of logs that occurred since the last poll. A filter must be created by calling either `eth_newFilter` or `eth_newBlockFilter`

### **getFilterLogs(index: `Index`): `Vec<Log>`**

* **interface**: `api.rpc.eth.getFilterLogs`
* **jsonrpc**: `eth_getFilterLogs`
* **summary**: Returns an array of all logs matching filter with given id.

### **getLogs(filter: `Filter`): `Vec<Log>`**

* **interface**: `api.rpc.eth.getLogs`
* **jsonrpc**: `eth_getLogs`
* **summary**: Returns an array of all logs matching a given filter object.

### **getStorageAt(address: `H160`, index: `U256`, number?: `BlockNumber`): `H256`**

* **interface**: `api.rpc.eth.getStorageAt`
* **jsonrpc**: `eth_getStorageAt`
* **summary**: Returns the value from a storage position at a given address.

### **getTransactionByBlockHashAndIndex(hash: `H256`, index: `Index`): `Transaction`**

* **interface**: `api.rpc.eth.getTransactionByBlockHash`
* **jsonrpc**: `eth_getTransactionByBlockHashAndIndex`
* **summary**: Returns information about a transaction by block hash and transaction index position.

### **getTransactionByBlockNumberAndIndex(number: `BlockNumber`, index: `Index`): `Transaction`**

* **interface**: `api.rpc.eth.getTransactionByBlockNumberAndIndex`
* **jsonrpc**: `eth_getTransactionByBlockNumberAndIndex`
* **summary**: Returns information about a transaction by block number and transaction index position.

### **getTransactionByHash(hash: `H256`): `Transaction`**

* **interface**: `api.rpc.eth.getTransactionByHash`
* **jsonrpc**: `eth_getTransactionByHash`
* **summary**: Returns information about a transaction for a given hash.

### **getTransactionCount(address: `H160`, number?: `BlockNumber`): `U256`**

* **interface**: `api.rpc.eth.getTransactionCount`
* **jsonrpc**: `eth_getTransactionCount`
* **summary**: Returns the number of transactions sent from an address.

### **getTransactionReceipt(hash: `H256`): `Receipt`**

* **interface**: `api.rpc.eth.getTransactionReceipt`
* **jsonrpc**: `eth_getTransactionReceipt`
* **summary**: Returns the receipt of a transaction by transaction hash.

### **maxPriorityFeePerGas(): `U256`**

* **interface**: `api.rpc.eth.maxPriorityFeePerGas`
* **jsonrpc**: `eth_maxPriorityFeePerGas`
* **summary**: Introduced in EIP-1159, a Geth-specific and simplified priority fee oracle.

### **newBlockFilter(): `U256`**

* **interface**: `api.rpc.eth.newBlockFilter`
* **jsonrpc**: `eth_newBlockFilter`
* **summary**: Creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call `eth_getFilterChanges`.

### **newFilter(filter: `Filter`): `U256`**

* **interface**: `api.rpc.eth.newFilter`
* **jsonrpc**: `eth_newFilter`
* **summary**: Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call `eth_getFilterChanges`

### **protocolVersion(): `u64`**

* **interface**: `api.rpc.eth.protocolVersion`
* **jsonrpc**: `eth_protocolVersion`
* **summary**: Returns the current Ethereum protocol version.

### **sendRawTransaction(bytes: `Bytes`): `H256`**

* **interface**: `api.rpc.eth.sendRawTransaction`
* **jsonrpc**: `eth_sendRawTransaction`
* **summary**: Submits a pre-signed transaction for broadcast to the network.

### **sendTransaction(request: `TransactionRequest`): `H256`**

* **interface**: `api.rpc.eth.sendTransaction`
* **jsonrpc**: `eth_sendTransaction`
* **summary**: Sends transaction; will block waiting for the signer to return the transaction hash.

### **syncing(): `SyncStatus`**

* **interface**: `api.rpc.eth.syncing`
* **jsonrpc**: `eth_syncing`
* **summary**: Returns an object with data about the sync status or false.

### **uninstallFilter(index: `Index`): `bool`**

* **interface**: `api.rpc.eth.uninstallFilter`
* **jsonrpc**: `eth_uninstallFilter`
* **summary**: Uninstalls a filter with given ID. Should always be called when watching is no longer needed. Additionally filters time out when not requested with `eth_getFilterChanges` for a period of time.


# grandpa

### **proveFinality(blockNumber: `BlockNumber`): `Option<EncodedFinalityProofs>`**

* **interface**: `api.rpc.grandpa.proveFinality`
* **jsonrpc**: `grandpa_proveFinality`
* **summary**: Proves finality for the given block number, returning the Justification for the last block in the set.

### **roundState(): `ReportedRoundStates`**

* **interface**: `api.rpc.grandpa.roundState`
* **jsonrpc**: `grandpa_roundState`
* **summary**: Returns the state of the current best round state as well as the ongoing background rounds.

### **subscribeJustifications(): `JustificationNotification`**

* **interface**: `api.rpc.grandpa.subscribeJustifications`
* **jsonrpc**: `grandpa_subscribeJustifications`
* **summary**: Subscribes to grandpa justifications.


# net

### **listening(): `bool`**

* **interface**: `api.rpc.net.listening`
* **jsonrpc**: `net_listening`
* **summary**: Returns true if client is actively listening for network connections. Otherwise false.

### **peerCount(): `Text`**

* **interface**: `api.rpc.net.peerCount`
* **jsonrpc**: `net_peerCount`
* **summary**: Returns number of peers connected to node.

### **version(): `Text`**

* **interface**: `api.rpc.net.version`
* **jsonrpc**: `net_version`
* **summary**: Returns protocol version.


# offchain

### **localStorageGet(kind: `StorageKind`, key: `Bytes`): `Option<Bytes>`**

* **interface**: `api.rpc.offchain.localStorageGet`
* **jsonrpc**: `offchain_localStorageGet`
* **summary**: Gets off-chain local storage under the given key and prefix.

### **localStorageSet(kind: `StorageKind`, key: `Bytes`, value: `Bytes`): `Null`**

* **interface**: `api.rpc.offchain.localStorageSet`
* **jsonrpc**: `offchain_localStorageSet`
* **summary**: Sets off-chain local storage under the given key and prefix.


# payment

### **queryFeeDetails(extrinsic: `Bytes`, at?: `BlockHash`): `FeeDetails`**

* **interface**: `api.rpc.payment.queryFeeDetails`
* **jsonrpc**: `payment_queryFeeDetails`
* **summary**: Queries the detailed fee of a given encoded extrinsic.
* **deprecated**: Use `api.call.transactionPaymentApi.queryFeeDetails` instead.

### **queryInfo(extrinsic: `Bytes`, at?: `BlockHash`): `RuntimeDispatchInfoV1`**

* **interface**: `api.rpc.payment.queryInfo`
* **jsonrpc**: `payment_queryInfo`
* **summary**: Retrieves the fee information for an encoded extrinsic.
* **deprecated**: Use `api.call.transactionPaymentApi.queryInfo` instead.


# rpc

### **methods(): `RpcMethods`**

* **interface**: `api.rpc.rpc.methods`
* **jsonrpc**: `rpc_methods`
* **summary**: Retrieves the list of RPC methods that are exposed by the node.


# state

### **call(method: `Text`, data: `Bytes`, at?: `BlockHash`): `Bytes`**

* **interface**: `api.rpc.state.call`
* **jsonrpc**: `state_call` (alias=`state_callAt`)
* **summary**: Calls a contract (pallet) at a block's state.

### **getChildReadProof(childStorageKey: `PrefixedStorageKey`, keys: `Vec<StorageKey>`, at?: `BlockHash`): `ReadProof`**

* **interface**: `api.rpc.state.getChildReadProof`
* **jsonrpc**: `state_getChildReadProof`
* **summary**: Returns proof of storage for child key entries at a specific block state.

### **getKeys(key: `StorageKey`, at?: `BlockHash`): `Vec<StorageKey>`**

* **interface**: `api.rpc.state.getKeys`
* **jsonrpc**: `state_getKeys`
* **summary**: Retrieves the keys with a certain prefix.
* **deprecated**: Use `api.rpc.state.getKeysPaged` to retrieve keys.

### **getKeysPaged(key: `StorageKey`, count: `u32`, startKey?: `StorageKey`, at?: `BlockHash`): `Vec<StorageKey>`**

* **interface**: `api.rpc.state.getKeysPaged`
* **jsonrpc**: `state_getKeysPaged` (alias=`state_getKeysPagedAt`)
* **summary**: Returns the keys with prefix with pagination support.

### **getMetadata(at?: `BlockHash`): `Metadata`**

* **interface**: `api.rpc.state.getMetadata`
* **jsonrpc**: `state_getMetadata`
* **summary**: Returns the runtime metadata.

### **getPairs(prefix: `StorageKey`, at?: `BlockHash`): `Vec<KeyValue>`**

* **interface**: `api.rpc.state.getPairs`
* **jsonrpc**: `state_getPairs`
* **summary**: Returns the keys with prefix, leaves empty to get all the keys (deprecated: Use getKeysPaged).
* **deprecated**: Use `api.rpc.state.getKeysPaged` to retrieve keys.

### **getReadProof(keys: `Vec<StorageKey>`, at?: `BlockHash`): `ReadProof`**

* **interface**: `api.rpc.state.getReadProof`
* **jsonrpc**: `state_getReadProof`
* **summary**: Returns proof of storage entries at a specific block state.

### **getRuntimeVersion(at?: `BlockHash`): `RuntimeVersion`**

* **interface**: `api.rpc.state.getRuntimeVersion`
* **jsonrpc**: `state_getRuntimeVersion` (alias=`chain_getRuntimeVersion`)
* **summary**: Gets the runtime version.

### **getStorage(key: `StorageKey`, at?: `BlockHash`): `StorageData`**

* **interface**: `api.rpc.state.getStorage`
* **jsonrpc**: `state_getStorage` (alias=`state_getStorageAt`)
* **summary**: Retrieves the storage for a key.

### **getStorageHash(key: `StorageKey`, at?: `BlockHash`): `Hash`**

* **interface**: `api.rpc.state.getStorageHash`
* **jsonrpc**: `state_getStorageHash` (alias=`state_getStorageHashAt`)
* **summary**: Retrieves the storage hash.

### **getStorageSize(key: `StorageKey`, at?: `BlockHash`): `u64`**

* **interface**: `api.rpc.state.getStorageSize`
* **jsonrpc**: `state_getStorageSize` (alias=`state_getStorageSizeAt`)
* **summary**: Retrieves the storage size.

### **queryStorage(keys: `Vec<StorageKey>`, fromBlock: `Hash`, toBlock?: `BlockHash`): `Vec<StorageChangeSet>`**

* **interface**: `api.rpc.state.queryStorage`
* **jsonrpc**: `state_queryStorage`
* **summary**: Queries historical storage entries (by key) starting from a start block.

### **queryStorageAt(keys: `Vec<StorageKey>`, at?: `BlockHash`): `Vec<StorageChangeSet>`**

* **interface**: `api.rpc.state.queryStorageAt`
* **jsonrpc**: `state_queryStorageAt`
* **summary**: Queries storage entries (by key) starting at block hash given as the second parameter.

### **subscribeRuntimeVersion(): `RuntimeVersion`**

* **interface**: `api.rpc.state.subscribeRuntimeVersion`
* **jsonrpc**: `state_subscribeRuntimeVersion`
* **summary**: Retrieves the runtime version via subscription.

### **subscribeStorage(keys?: `Vec<StorageKey>`): `StorageChangeSet`**

* **interface**: `api.rpc.state.subscribeStorage`
* **jsonrpc**: `state_subscribeStorage`
* **summary**: Subscribes to storage changes for the provided keys.

### **traceBlock(block: `Hash`, targets: `Option<Text>`, storageKeys: `Option<Text>`, methods: `Option<Text>`): `TraceBlockResponse`**

* **interface**: `api.rpc.state.traceBlock`
* **jsonrpc**: `state_traceBlock`
* **summary**: Provides a way to trace the re-execution of a single block.


# system

### **accountNextIndex(accountId: `AccountId`): `Index`**

* **interface**: `api.rpc.system.accountNextIndex`
* **jsonrpc**: `system_accountNextIndex`
* **summary**: Retrieves the next accountIndex as available on the node.

### **addLogFilter(directives: `Text`): `Null`**

* **interface**: `api.rpc.system.addLogFilter`
* **jsonrpc**: `system_addLogFilter`
* **summary**: Adds the supplied directives to the current log filter.

### **addReservedPeer(peer: `Text`): `Text`**

* **interface**: `api.rpc.system.addReservedPeer`
* **jsonrpc**: `system_addReservedPeer`
* **summary**: Adds a reserved peer.

### **chain(): `Text`**

* **interface**: `api.rpc.system.chain`
* **jsonrpc**: `system_chain`
* **summary**: Retrieves the chain.

### **chainType(): `ChainType`**

* **interface**: `api.rpc.system.chainType`
* **jsonrpc**: `system_chainType`
* **summary**: Retrieves the chain type.

### **dryRun(extrinsic: `Bytes`, at?: `BlockHash`): `ApplyExtrinsicResult`**

* **interface**: `api.rpc.system.dryRun`
* **jsonrpc**: `system_dryRun` (alias=`system_dryRunAt`)
* **summary**: Dry runs an extrinsic at a given block.

### **health(): `Health`**

* **interface**: `api.rpc.system.health`
* **jsonrpc**: `system_health`
* **summary**: Returns the health status of the node.

### **localListenAddresses(): `Vec<Text>`**

* **interface**: `api.rpc.system.localListenAddresses`
* **jsonrpc**: `system_localListenAddresses`
* **summary**: The addresses include a trailing /p2p/ with the local PeerId, and are thus suitable to be passed to addReservedPeer or as a bootnode address for example.

### **localPeerId(): `Text`**

* **interface**: `api.rpc.system.localPeerId`
* **jsonrpc**: `system_localPeerId`
* **summary**: Returns the base58-encoded PeerId of the node.

### **name(): `Text`**

* **interface**: `api.rpc.system.name`
* **jsonrpc**: `system_name`
* **summary**: Retrieves the node name.

### **nodeRoles(): `Vec<NodeRole>`**

* **interface**: `api.rpc.system.nodeRoles`
* **jsonrpc**: `system_nodeRoles`
* **summary**: Returns the roles the node is running as.

### **peers(): `Vec<PeerInfo>`**

* **interface**: `api.rpc.system.peers`
* **jsonrpc**: `system_peers`
* **summary**: Returns the currently connected peers.

### **properties(): `ChainProperties`**

* **interface**: `api.rpc.system.properties`
* **jsonrpc**: `system_properties`
* **summary**: Gets a custom set of properties as a JSON object, defined in the chain specification.

### **removeReservedPeer(peerId: `Text`): `Text`**

* **interface**: `api.rpc.system.removeReservedPeer`
* **jsonrpc**: `system_removeReservedPeer`
* **summary**: Removes a reserved peer.

### **reservedPeers(): `Vec<Text>`**

* **interface**: `api.rpc.system.reservedPeers`
* **jsonrpc**: `system_reservedPeers`
* **summary**: Returns the list of reserved peers.

### **resetLogFilter(): `Null`**

* **interface**: `api.rpc.system.resetLogFilter`
* **jsonrpc**: `system_resetLogFilter`
* **summary**: Resets the log filter to Substrate defaults.

### **syncState(): `SyncState`**

* **interface**: `api.rpc.system.syncState`
* **jsonrpc**: `system_syncState`
* **summary**: Returns the state of the syncing of the node.

### **version(): `Text`**

* **interface**: `api.rpc.system.version`
* **jsonrpc**: `system_version`
* **summary**: Retrieves the version of the node.


# trace

### **filter(filter: `FilterRequest`): `Vec<TransactionTrace>`**

* **interface**: `api.rpc.trace.filter`
* **jsonrpc**: `trace_filter`
* **summary**: It allows you to get the traces of multiple transactions in a single request based on the filters you provide.


# txpool

### **content():** `TxPoolResult<PoolTransactionMap<PoolTransaction>>`

* **interface**: `api.rpc.txpool.content`
* **jsonrpc**: `txpool_content`
* **summary**: Lists the exact details of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only.

### **inspect(): `TxPoolResult<PoolTransactionMap<PoolSummary>>`**

* **interface**: `api.rpc.txpool.inspect`
* **jsonrpc**: `txpool_inspect`
* **summary**: Lists a textual summary of all the transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only.

### **status(): `TxPoolResult<U256>`**

* **interface**: `api.rpc.txpool.status`
* **jsonrpc**: `txpool_status`
* **summary**: Lists the number of transactions currently pending for inclusion in the next block(s), as well as the ones that are being scheduled for future execution only.


# web3

### **clientVersion(): `String`**

* **interface**: `api.rpc.web3.clientVersion`
* **jsonrpc**: `web3_clientVersion`
* **summary**: Returns current client version.

### **sha3(): `H256`**

* **interface**: `api.rpc.web3.sha3`
* **jsonrpc**: `web3_sha3`
* **summary**: Returns sha3 of the given data.


# Explorer API

## The Bifrost Network Explorer

The Bifrost Explorer provides a web page and a wide range of APIs for DApp developers for convenience.

|         |                                                                                           |
| ------- | ----------------------------------------------------------------------------------------- |
| Mainnet | <https://explorer.mainnet.thebifrost.io>                                                  |
| Testnet | [https://explorer.testnet.thebifrost.io](https://explorer.testnet.thebifrost.io/api-docs) |

You can find all API specifications on the [Explorer API Documentation page](https://explorer.testnet.thebifrost.io/api-docs).


# Runtime API

External node components handle most of the logic such as peer discovery, transaction pooling, block and transaction propagations, consensus mechanisms, and RPC requests. In some cases, external components require some data that is provided by the Runtime. Thus, the Runtime API allows the Runtime and external components to communicate easily with each other.

The API definitions below are the Runtime APIs supported on the Bifrost Network.

### **AccountNonceApi**

**accountNonce(accountId: `AccountId`): `Index`**

* **interface**: `api.call.accountNonceApi.accountNonce`
* **runtime**: `AccountNonceApi_account_nonce`
* **summary**: The API to query account nonce (aka transaction index).

###

### **AuraApi**

**authorities(): `Vec<AuthorityId>`**

* **interface**: `api.call.auraApi.authorities`
* **runtime**: `AuraApi_authorities`
* **summary**: Returns the current set of authorities.

**slotDuration(): `SlotDuration`**

* **interface**: `api.call.auraApi.slotDuration`
* **runtime**: `AuraApi_slot_duration`
* **summary**: Returns the slot duration for Aura.

###

### **BlockBuilder**

**applyExtrinsic(extrinsic: `Extrinsic`): `ApplyExtrinsicResult`**

* **interface**: `api.call.blockBuilder.applyExtrinsic`
* **runtime**: `BlockBuilder_apply_extrinsic`
* **summary**: Applies the given extrinsic.

**checkInherents(block: `Block`, data: `InherentData`): `CheckInherentsResult`**

* **interface**: `api.call.blockBuilder.checkInherents`
* **runtime**: `BlockBuilder_check_inherents`
* **summary**: Checks that the inherents are valid.

**finalizeBlock(): `Header`**

* **interface**: `api.call.blockBuilder.finalizeBlock`
* **runtime**: `BlockBuilder_finalize_block`
* **summary**: Finishes the current block.

**inherentExtrinsics(inherent: `InherentData`): `Vec<Extrinsic>`**

* **interface**: `api.call.blockBuilder.inherentExtrinsics`
* **runtime**: `BlockBuilder_inherent_extrinsics`
* **summary**: Generates inherent extrinsics.

###

### **ConvertTransactionRuntimeApi**

**convertTransaction(transaction: `TransactionV2`): `Extrinsic`**

* **interface**: `api.call.convertTransactionRuntimeApi.convertTransaction`
* **runtime**: `ConvertTransactionRuntimeApi_convert_transaction`
* **summary**: Converts an Ethereum-style transaction to Extrinsic

###

### **Core**

**executeBlock(block: `Block`): `Null`**

* **interface**: `api.call.core.executeBlock`
* **runtime**: `Core_execute_block`
* **summary**: Executes the given block.

**initializeBlock(header: `Header`): `Null`**

* **interface**: `api.call.core.initializeBlock`
* **runtime**: `Core_initialize_block`
* **summary**: Initializes a block with the given header.

**version(): `RuntimeVersion`**

* **interface**: `api.call.core.version`
* **runtime**: `Core_version`
* **summary**: Returns the version of the runtime.

###

### **DebugRuntimeApi**

**traceBlock(extrinsics: `Vec<Extrinsic>`, knownTransactions: `Vec<H256>`): `Result<(), DispatchError>`**

* **interface**: `api.call.debugRuntimeApi.traceBlock`
* **runtime**: `DebugRuntimeApi_trace_block`
* **summary**: Traces all block extrinsics.

**traceTransaction(extrinsics: `Vec<Extrinsic>`, transaction: `EthTransaction`): `Result<(), DispatchError>`**

* **interface**: `api.call.debugRuntimeApi.traceTransaction`
* **runtime**: `DebugRuntimeApi_trace_transaction`
* **summary**: Traces transaction extrinsics.

###

### **EthereumRuntimeRPCApi**

**accountBasic(address: `H160`): `EvmAccount`**

* **interface**: `api.call.ethereumRuntimeRPCApi.accountBasic`
* **runtime**: `EthereumRuntimeRPCApi_account_basic`
* **summary**: Returns pallet\_evm::Accounts basic information by address.

**accountCodeAt(address: `H160`): `Bytes`**

* **interface**: `api.call.ethereumRuntimeRPCApi.accountCodeAt`
* **runtime**: `EthereumRuntimeRPCApi_account_code_at`
* **summary**: Returns pallet\_evm::AccountCodes for a given account address.

**author(): `H160`**

* **interface**: `api.call.ethereumRuntimeRPCApi.author`
* **runtime**: `EthereumRuntimeRPCApi_author`
* **summary**: Returns the converted FindAuthor::find\_author authority id.

**call(from: `H160`, to: `H160`, data: `Vec<u8>`, value: `U256`, gasLimit: `U256`, maxFeePerGas: `Option<U256>`, maxPriorityFeePerGas: `Option<U256>`, nonce: `Option<U256>`, estimate: `bool`, accessList: `Option<Vec<(H160, Vec<H256>)>>`): `Result<EvmCallInfo, DispatchError>`**

* **interface**: `api.call.ethereumRuntimeRPCApi.call`
* **runtime**: `EthereumRuntimeRPCApi_call`
* **summary**: Returns a pallet\_ethereum::call response.

**chainId(): `u64`**

* **interface**: `api.call.ethereumRuntimeRPCApi.chainId`
* **runtime**: `EthereumRuntimeRPCApi_chain_id`
* **summary**: Returns runtime defined pallet\_evm::ChainId.

**create(from: `H160`, data: `Vec<u8>`, value: `U256`, gasLimit: `U256`, maxFeePerGas: `Option<U256>`, maxPriorityFeePerGas: `Option<U256>`, nonce: `Option<U256>`, estimate: `bool`, accessList: `Option<Vec<(H160, Vec<H256>)>>`): `Result<EvmCreateInfo, DispatchError>`**

* **interface**: `api.call.ethereumRuntimeRPCApi.create`
* **runtime**: `EthereumRuntimeRPCApi_create`
* **summary**: Returns a pallet\_ethereum::call response.

**currentAll(): `(Option<BlockV2>, Option<Vec<EthReceiptV3>>, Option<Vec<EthTransactionStatus>>)`**

* **interface**: `api.call.ethereumRuntimeRPCApi.currentAll`
* **runtime**: `EthereumRuntimeRPCApi_current_all`
* **summary**: Returns all the current data for a block in a single runtime call.

**currentBlock(): `BlockV2`**

* **interface**: `api.call.ethereumRuntimeRPCApi.currentBlock`
* **runtime**: `EthereumRuntimeRPCApi_current_block`
* **summary**: Returns the current block.

**currentReceipts(): `Option<Vec<EthReceiptV3>>`**

* **interface**: `api.call.ethereumRuntimeRPCApi.currentReceipts`
* **runtime**: `EthereumRuntimeRPCApi_current_receipts`
* **summary**: Returns the current receipt.

**currentTransactionStatuses(): `Option<Vec<EthTransactionStatus>>`**

* **interface**: `api.call.ethereumRuntimeRPCApi.currentTransactionStatuses`
* **runtime**: `EthereumRuntimeRPCApi_current_transaction_statuses`
* **summary**: Returns the current transaction status.

**elasticity(): `Option<Permill>`**

* **interface**: `api.call.ethereumRuntimeRPCApi.elasticity`
* **runtime**: `EthereumRuntimeRPCApi_elasticity`
* **summary**: Returns the elasticity multiplier.

**extrinsicFilter(xts: `Vec<Extrinsic>`): `Vec<TransactionV2>`**

* **interface**: `api.call.ethereumRuntimeRPCApi.extrinsicFilter`
* **runtime**: `EthereumRuntimeRPCApi_extrinsic_filter`
* **summary**: Receives a `Vec<OpaqueExtrinsic>` and filters all the ethereum transactions.

**gasPrice(): `u256`**

* **interface**: `api.call.ethereumRuntimeRPCApi.gasPrice`
* **runtime**: `EthereumRuntimeRPCApi_gas_price`
* **summary**: Returns FixedGasPrice::min\_gas\_price

**storageAt(address: `H160`, index: `u256`): `H256`**

* **interface**: `api.call.ethereumRuntimeRPCApi.storageAt`
* **runtime**: `EthereumRuntimeRPCApi_storage_at`
* **summary**: Returns pallet\_evm::AccountStorages for a given account address and index.&#x20;

###

### **GrandpaApi**

**currentSetId(): `SetId`**

* **interface**: `api.call.grandpaApi.currentSetId`
* **runtime**: `GrandpaApi_current_set_id`
* **summary**: Gets current GRANDPA authority set id.

**generateKeyOwnershipProof(setId: `SetId`, authorityId: `AuthorityId`): `Option<OpaqueKeyOwnershipProof>`**

* **interface**: `api.call.grandpaApi.generateKeyOwnershipProof`
* **runtime**: `GrandpaApi_generate_key_ownership_proof`
* **summary**: Generates a proof of key ownership for the given authority in the given set.

**grandpaAuthorities(): `AuthorityList`**

* **interface**: `api.call.grandpaApi.grandpaAuthorities`
* **runtime**: `GrandpaApi_grandpa_authorities`
* **summary**: Gets the current GRANDPA authorities and weights. This should not change except when changes are scheduled and the corresponding delay has passed.

**submitReportEquivocationUnsignedExtrinsic(equivocationProof: `GrandpaEquivocationProof`, keyOwnerProof: `OpaqueKeyOwnershipProof`): `Option<Null>`**

* **interface**: `api.call.grandpaApi.submitReportEquivocationUnsignedExtrinsic`
* **runtime**: `GrandpaApi_submit_report_equivocation_unsigned_extrinsic`
* **summary**: Submits an unsigned extrinsic to report an equivocation.

###

### **Metadata**

**metadata(): `OpaqueMetadata`**

* **interface**: `api.call.metadata.metadata`
* **runtime**: `Metadata_metadata`
* **summary**: Returns the metadata of a runtime.

###

### **OffchainWorkerApi**

**offchainWorker(header: `Header`): `Null`**

* **interface**: `api.call.offchainWorkerApi.offchainWorker`
* **runtime**: `OffchainWorkerApi_offchain_worker`
* **summary**: Starts the off-chain task for the given block header.

###

### **SessionKeys**

**decodeSessionKeys(encoded: `Bytes`): `Option<Vec<(Bytes, KeyTypeId)>>`**

* **interface**: `api.call.sessionKeys.decodeSessionKeys`
* **runtime**: `SessionKeys_decode_session_keys`
* **summary**: Decodes the given public session keys.

**generateSessionKeys(seed: `Option<Bytes>`): `Bytes`**

* **interface**: `api.call.sessionKeys.generateSessionKeys`
* **runtime**: `SessionKeys_generate_session_keys`
* **summary**: Generates a set of session keys with optionally using the given seed.

###

### **TaggedTransactionQueue**

**validateTransaction(source: `TransactionSource`, tx: `Extrinsic`, blockHash: `BlockHash`): `TransactionValidity`**

* **interface**: `api.call.taggedTransactionQueue.validateTransaction`
* **runtime**: `TaggedTransactionQueue_validate_transaction`
* **summary**: Validates the transaction.

###

### **TransactionPaymentApi**

**queryFeeDetails(uxt: `Extrinsic`, len: `u32`): `FeeDetails`**

* **interface**: `api.call.transactionPaymentApi.queryFeeDetails`
* **runtime**: `TransactionPaymentApi_query_fee_details`
* **summary**: The transaction fee details.

**queryInfo(uxt: `Extrinsic`, len: `u32`): `RuntimeDispatchInfo`**

* **interface**: `api.call.transactionPaymentApi.queryInfo`
* **runtime**: `TransactionPaymentApi_query_info`
* **summary**: The transaction info.


# Cross-Chain Transaction and Oracle API


# Price Oracle Contract API

## Description

One of the key advantages of the Bifrost Network is its native price oracle, which offers a wide range of digital asset prices sourced from centralized exchanges (CEXs) and decentralized exchanges (DEXs) on other networks. We have made the price oracle for CCCP-supported assets publicly available to all developers on the Bifrost Network. We hope many DApp developers will enjoy these benefits through our network.

To minimize the learning curve, our oracle service includes an abstraction layer that provides an interface compatible with Chainlink's. This design choice not only reduces the time needed for developers to adapt but also enables seamless integration for those already familiar with Chainlink's environment.&#x20;

In the following sections, we will explain how to utilize Bifrost's price oracle.

## Price Feed Methods

### decimals()

Returns USD price decimals for a specific asset (e.g., the USD price of ETH).

#### **Return values**

<table><thead><tr><th width="111">Name</th><th width="95">Type</th><th>Description</th></tr></thead><tbody><tr><td></td><td>uint8</td><td>The decimals (now only USD support)  for a specific asset</td></tr></tbody></table>

### description()

Return the type of a specific oracle feeder (e.g., ETH/USD)

#### Return values

<table><thead><tr><th width="111">Name</th><th width="100">Type</th><th>Description</th></tr></thead><tbody><tr><td></td><td>string</td><td>The type of a specific oracle feeder </td></tr></tbody></table>

### version()

Return the version of a specific oracle feed contract.

#### Return values

<table><thead><tr><th width="111">Name</th><th width="99">Type</th><th>Description</th></tr></thead><tbody><tr><td></td><td>uint256</td><td>The version of a specific oracle feed contract. </td></tr></tbody></table>

### getRoundData(\_roundId)

Return the price information from the previous round along with the timestamp of that update.

#### Parameters

<table><thead><tr><th width="130">Name</th><th width="99">Type</th><th>Description</th></tr></thead><tbody><tr><td>_roundId</td><td>uint8</td><td>The round ID of desired price information. </td></tr></tbody></table>

#### Return values

<table><thead><tr><th width="192">Name</th><th width="99">Type</th><th>Description</th></tr></thead><tbody><tr><td>roundId</td><td>uint80</td><td>The round ID.</td></tr><tr><td>answer</td><td>int256</td><td>The price information for this round.</td></tr><tr><td>startedAt</td><td>uint256</td><td>The timestamp of when the round started.</td></tr><tr><td>updatedAt</td><td>uint256</td><td>The timestamp of when the round was updated.</td></tr><tr><td>answeredInRound</td><td>uint80</td><td>The answers could take multiple rounds to be computed.</td></tr></tbody></table>

### latestRoundData()

Return the latest price information along with the timestamp of the most recent update.

#### Return values

<table><thead><tr><th width="192">Name</th><th width="99">Type</th><th>Description</th></tr></thead><tbody><tr><td>roundId</td><td>uint80</td><td>The round ID.</td></tr><tr><td>answer</td><td>int256</td><td>The price information for this round.</td></tr><tr><td>startedAt</td><td>uint256</td><td>The timestamp of when the round started.</td></tr><tr><td>updatedAt</td><td>uint256</td><td>The timestamp of when the round was updated.</td></tr><tr><td>answeredInRound</td><td>uint80</td><td>The answers could take multiple rounds to be computed.</td></tr></tbody></table>

## Price Feed Contract Interface

```solidity
interface IAccessControlledOffchainAggregator {
  function decimals() external view returns (uint8);
  function description() external view returns (string memory);
  function version() external pure returns (uint256);
  function getRoundData(uint80 _roundId) external view
  returns (
    uint80 roundId,
    int256 answer,
    uint256 startedAt,
    uint256 updatedAt,
    uint80 answeredInRound
  );
  function latestRoundData() external view
  returns (
    uint80 roundId,
    int256 answer,
    uint256 startedAt,
    uint256 updatedAt,
    uint80 answeredInRound
  );
}
```

## Price Feed Contract Address

<table><thead><tr><th width="170">Asset/Fiat Type</th><th>Contract Address (mainnet/testnet)</th></tr></thead><tbody><tr><td>ETH/USD</td><td><strong>mainnet</strong>: <code>0x0427d2908E45FAfD65F56a6A6E2095461e70A3d6</code><br><strong>testnet</strong>: <code>0x786cA38641bD2eE6f4c9397056F9CF9d9C893eEA</code></td></tr><tr><td>USDC/USD</td><td><strong>mainnet</strong>: <code>0x2FFc2e7C4c280eb82A13972cCA30719F9365746F</code><br><strong>testnet</strong>: <code>0x9Fa06A8f3454b902b4ecdaBB6eBC8F56CC536609</code></td></tr><tr><td>BNB/USD</td><td><strong>mainnet</strong>: <code>0x1Eda422B45b279c8C280B510cbf4BDFB671985c0</code><br><strong>testnet</strong>: <code>0x590A94102B03b10d4aDF8bfc83aCC556dc9745E5</code></td></tr><tr><td>MATIC/USD</td><td><strong>mainnet</strong>: <code>0x59C75485126Ac9a90609E7Fe5D6c513396ED503d</code><br><strong>testnet</strong>: <code>0x534Fa69E2616444B5DFB940f3a893D8183fEDcD7</code></td></tr><tr><td>BIFI/USD</td><td><strong>mainnet</strong>: <code>0xc97D3b8d03ec813b760C8A471F3c8393e4F91506</code><br><strong>testnet</strong>: <code>0x42acD3003fA8b870999573071427C64A90146991</code></td></tr><tr><td>BFC/USD</td><td><strong>mainnet</strong>: <code>0x77397a130c169702Ff007682630eCAa5caB23791</code><br><strong>testnet</strong>: <code>0xEF746B668880f83F06245245017B31523e485Df8</code></td></tr><tr><td>USDT/USD</td><td><strong>mainnet</strong>: <code>0xd8653315Dc63128AA8428C6Ae12E50b5E77156AC</code><br><strong>testnet</strong>: <code>0xfdcC92216E7236E6f0A2033B1d63D3505369945b</code></td></tr><tr><td>DAI/USD</td><td><strong>mainnet</strong>: <code>0xF2385A5DDa77fF9731F661aA44f6b4398A97A1cd</code><br><strong>testnet</strong>: <code>0x4842D3a8c29fABfB971AeD8675262c16b71ef2Dd</code></td></tr><tr><td>WBTC/USD</td><td><strong>mainnet</strong>: <code>0xc1596ece7e801125D507f0815e7070Aa97D3645e</code><br><strong>testnet</strong>: <code>0x1aF3595Ba40EAb3481f19245E5a0F09018e85Aa4</code></td></tr><tr><td>BTCB/USD</td><td><strong>mainnet</strong>: <code>0x40c8BB8036351EF29b41ea8AFEbA76ac2d8A96bF</code><br><strong>testnet</strong>: <code>0x0B2C85312E35829e714Fef01efAD6d2718e3c227</code></td></tr></tbody></table>

## Example: ETH/USD price oracle (testnet)

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IAccessControlledOffchainAggregator {
  function decimals() external view returns (uint8);
  function description() external view returns (string memory);
  function version() external pure returns (uint256);
  function getRoundData(uint80 _roundId) external view
  returns (
    uint80 roundId,
    int256 answer,
    uint256 startedAt,
    uint256 updatedAt,
    uint80 answeredInRound
  );
  function latestRoundData() external view
  returns (
    uint80 roundId,
    int256 answer,
    uint256 startedAt,
    uint256 updatedAt,
    uint80 answeredInRound
  );
}

contract ChainlinkPriceOracle {
    IAccessControlledOffchainAggregator internal priceFeed;

    constructor() {
        // ETH / USD price oracle address (testnet)
        priceFeed = IAccessControlledOffchainAggregator(0x786cA38641bD2eE6f4c9397056F9CF9d9C893eEA);
    }

    function getLatestPrice() public view returns (int) {
        (
            uint80 roundID,
            int price,
            uint startedAt,
            uint timeStamp,
            uint80 answeredInRound
        ) = priceFeed.latestRoundData();
        // for ETH / USD price is scaled up by 10 ** 8
        return price / 1e8;
    }
}
```


# Socket Contract API

The ***vault contract*** is an entry point for a user request. When a user requests *Bridge* or *BridgeAndCall* with their cryptocurrency, the vault contract securely locks it until the opposite-directional bridge request occurs.

The ***socket contract*** receives and verifies event messages from users or relayers. If the requested message is determined as valid, the socket contract executes request-indicated actions (e.g. mint, lending, leveraged investment) and checks whether or not these actions are executed correctly.

## Interfaces of Vault contract

```solidity
interface IVault {
    // Events that occur when a user's request is generated or an asset is processed
    event Vault(uint8 type_, uint128 asset_id_, uint256 amount_);
    
    // Function that returns the address of the associated WBFC
    function WBFC() view returns (address);
    // Function that returns the address of the associated socket
    function socket() view returns (address);
    // Function that returns the address of the associated swap router
    function swap_router() view returns (address);
    
    // Entry point for the user to initiate a CCCP request
    function request(User_Request memory user_request) payable returns (bool);
    // Entry point for socket to execute user request
    function execute(Instruction memory instruction) returns (bool);
    // Entry point for socket to complete user request
    function resolve(Task_Params memory params) returns (bool);
    // Entry point for socket to rollback user request
    function rollback(Task_Params memory params) returns (bool);
    // Entry point to provide the liquidity
    function liquidity_deposit(uint128 _asset_index, uint256 _amount) payable returns ();
    
    // Function that returns a value that identifies the native coin in which the contract was deployed
    function this_chain_coin_index() view returns (uint128);
    // Function that returns the fee rate
    function fee_rate() view returns (uint256);
    
    // Function that returns the handler address of the associated lending service
    function lending_handlers(uint128) view returns (address);
    
    // Function that returns a value that identifies the asset(coin, token)
    function get_asset_id(address) view returns (uint128);
    // Function that returns a token(coin) registered with an asset identification value
    function assets(uint128) view returns (AssetInfo memory asset_info);

    struct Asset_Config {
        uint128 min_amount;
        uint128 max_amount;
        uint32 _type;
        uint64 fee_rate;
        address target;
    }
    struct AssetInfo {
        Asset_Config config;
        uint256 amount;
        uint256 fee;
    }
    struct User_Request {
        Instruction ins_code;
        Task_Params params;
    }

    struct Instruction {
        ChainIndex chain;
        RBCmethod method;
    }
    struct Task_Params {
        Asset_Index tokenIDX0; Asset_Index tokenIDX1;
        address refund;
        address to;
        uint256 amount;
        bytes variants;
    }
}
```

## Interfaces of Socket contract

```solidity
interface ISocket {
    // Events that occur when relayer submits a round_up poll or when the round_up poll reaches majority
    event RoundUp(Task_Status status, Round_Up_Submit roundup);
    // An event that occurs when a user generates a request or when the request state is transitioned by relayer's poll
    event Socket(Socket_Message msg);
    
    // Entry point for user requests passed by Vault
    function user_executor(User_Request calldata request) external returns (bool)
    // Entry point for relayer to process user requests
    function poll(Poll_Submit calldata _submit) external returns (bool returnData)
    // Entry point for user to rollback unprocessed requests
    function timeout_rollback(RequestID calldata request, User_Request calldata _req) external returns (bool)
    
    // Function that returns a filter that records whether relayer has properly "poll" for the request
    function get_poll_filter(RequestID calldata _rid, address _sender) external view returns (uint256)
    // Function that returns stored request information
    function get_request(RequestID calldata _rid) external view returns(RequestInfo memory)
    // Function that returns signature information submitted by relayer for round update
    function get_round_signatures(uint256 _round) external view returns (Signatures memory)
    // Function that returns the signature submitted by relayer for processing the user's request
    function get_signatures(RequestID memory _rid, Task_Status _status) external view returns (Signatures memory)
    
    // Function that returns the address of the associated authority
    function authority() view returns (address)
    // Function that returns the address of the associated oracle manager
    function orc_manager() view returns (address)
    // Function that returns the address of the associated vault
    function vault() view returns (address)
    
    // Function that returns a value that identifies the chain in which the contract was deployed
    function this_chain() view returns (uint64)
    // Function that returns the number of requests generated by the user
    function sequence() view returns (uint128)
    // Function that returns a timeout value for rollback
    function timeout_blocks() view returns (uint256)
    
    // Entry point for relayer to update the round of native network
    function round_control_relay(Round_Up_Submit calldata _round_up_submit) external returns (bool)
    
    // --- only on BIFROST network ---
    
    // The entry point for relayer to feed Oracle of aggregate type
    function oracle_aggregate_feeding(Oracle_ID[] memory oids, bytes32[] memory data) onlyRelayer external returns (bool)
    // The entry point for relayer to feed Oracle of consensus type
    function oracle_consensus_feeding(Oracle_ID[] memory oids, uint128[] memory rounds, bytes32[] memory data) onlyRelayer external returns (bool)
    // The entry point for submitting a signature to update the round of the native network
    function round_control_poll(Round_Up_Submit calldata _round_up_submit) external returns (bool)

    type ChainIndex is uint64;
    type RBCmethod is uint64;
    type Asset_Index is uint128;
    type Oracle_ID is bytes32;

    struct Socket_Message {
        RequestID req_id;
        Task_Status status;
        Instruction ins_code;
        Task_Params params;
    }

    struct Poll_Submit {
        Socket_Message msg;
        Signatures sigs;
        uint256 option;
    }

    struct Instruction {
        ChainIndex chain;
        RBCmethod method;
    }

    struct Task_Params {
        Asset_Index tokenIDX0; Asset_Index tokenIDX1;
        address refund;
        address to;
        uint256 amount;
        bytes variants;
    }

    struct RequestID {
        ChainIndex chain;
        uint64 round_id;
        uint128 sequence;
    }

    struct Signatures {
        bytes32[] r;
        bytes32[] s;
        bytes     v;
    }

    struct Round_Up_Submit {
        uint256 round;
        address[] new_relayers;
        Signatures sigs;
    }

    enum Task_Status {
        None,
        Requested,
        Failed,
        Executed,
        Reverted,
        Accepted,
        Rejected,
        Committed,
        Rollbacked,
        Round_Up,
        Round_Up_Committed
    }
}
```


# Testnet Faucet

This page introduces how to claim BFC in order to test functions or carry out missions on the Bifrost Testnet. Through the faucet, you can claim BFC on the testnet which has no value.

### Joining Discord

The Bifrost Testnet Faucet will be operated by a Discord bot. Please visit our [Bifrost CITY](https://discord.gg/bifrostcity) server.

### Commands

On the faucet, three types of commands are supported. Enter a command in the **faucet** channel of the [Bifrost CITY](https://discord.gg/bifrostcity) server, and the command will be executed.

Please read below to learn how each command works.

#### /faucet\_help

Command `/faucet_help` shows the list of commands and explanations for each command.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FRaFVgByHgSkoWO9Xs0ef%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-05-11%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.10.39.png?alt=media&amp;token=fa1a7e16-e5fb-4e8d-9010-6b39faf6b71d" alt=""><figcaption></figcaption></figure>

#### /faucet \[address]

With command `/faucet [address]`, you can receive testnet BFC in the entered address. BFC can be used when testing internal services of the Bifrost Testnet, or cross-chain actions (Bifrost Testnet → External networks)

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FEbJ4XnUSRryO2nj1ExcD%2Fimage.png?alt=media&amp;token=1081bf49-aee5-4b64-935a-9dd384497138" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FPuJINgY21vnxhIU4Qm66%2Fimage.png?alt=media&amp;token=170eb99b-367f-4cf7-b4f7-3fa1ecdd58ff" alt=""><figcaption></figcaption></figure>

Once a request is sent, the bot starts to transfer BFC to the entered address. If the process is successfully done, you will be notified and given the Bifrost explorer link. You can use command `/faucet [address]` every 24 hours per Discord account.


# Governance

This page outlines the governance mechanism of the Bifrost Network during the Incentivized Testnet.

## **Introduction**&#x20;

Bifrost aims to reflect the voice of the community and enhance the protocol through governance. Based on our shared vision, the Bifrost governance mechanism encompasses all token holders. All types of governance must go through the decisions of holders who can vote or create proposals. In addition, our governance forum allows everyone, even those without tokens, to freely discuss and share ideas about the protocol.

## Glossary

* **Referendum**: The proposal with the highest amount of support from each launch period is selected to be a referendum. During the voting period, BFC holders can submit “aye” or “nay” votes by depositing their shares, and approval is determined by the total voting weight at the end of the voting period.&#x20;
* **Launch period**: A period of time with blocks of a certain length. At the end of the launch period, the proposal with the most endorsement is selected for a referendum.&#x20;
* **Voting period**: A period of time during which voters may vote on a referendum. At the end of the voting period, votes are aggregated to determine whether or not a referendum is approved.&#x20;
* **Enactment period**: A period of time it takes for a referendum to be reflected in the network. From a technical perspective, a referendum is placed In Queue, waits for a certain amount of time specified by the enactment period, and is finally applied by `pallet_scheduler`.&#x20;
* **Lock period**: A period of time starting from the end of the enactment period of a referendum during which the voters’ shares are locked.&#x20;
* **Delegation**: As it may be difficult for BFC holders to participate in every voting, delegation exists as an option to yield one’s voting rights by using their stakes as collateral and increasing the voting weight of a certain trusted voter. In such a case, when the delegated voter casts their vote, it is submitted with an additional delegated weight. As with normal voting, a conviction can be applied to delegation to increase the vote weight by increasing the lock period. However, delegators cannot vote unless they remove their delegation.

## Mechanics

The idea behind governance is to allow holders to make changes to the Bifrost Network through voting. Every proposal has to go through a referendum.

Members of the General Council are expected to have a deep understanding of the Bifrost Network and be aligned with its long-term goals. Initially, General Council will be appointed by the Bifrost Foundation, and over time will move towards the election-based system in which BFC holders will be voting members in and out.

## Proposal

### Creating a proposal

In order to submit proposals, participants must first create a proposal. During the process, participants suggest changes to the pallet (smart contract) and the extrinsic (function). Once participants make all the changes, they have to save the generated hash.&#x20;

The saved hash is used to submit a proposal. When submitting a proposal, holders can set the minimum amount of BFC to endorse the proposal. Keep in mind that the minimum amount of BFC will be locked until the proposal is selected as a referendum and undergoes voting. This is a measure to prevent voters from selling their votes after endorsement. The required number of coins may vary depending on the type of the proposal or the minimum number set by the proposal creator.&#x20;

If a proposal fails to become a referendum, it has to go through another launch period. The process is repeated until the proposal is selected as a referendum. At the end of every launch period, the proposal with the most endorsement will be selected for a referendum.

### **Endorsing a proposal**

Voters can endorse a proposal by clicking the “Endorse” button. The endorsement may fail if a voter does not have enough coins in their address or does not own enough coins set by the proposal creator.

### Referenda

Given that at least one proposal is endorsed by the majority by the end of a launch period, a new referendum is held after every voting period. During the voting period, holders may vote either “aye” or “nay”. If a referendum passes, it goes through the enactment period and is queued for dispatch.&#x20;

The number of coins determines the voting power in the referendum and holders can vote on behalf of other voters through delegation. When voting on the referendum either with “aye” or “nay”, voters can use the “Increase voting power” button to increase their conviction.&#x20;

Voters can increase their voting power by increasing their lock period. With this feature, voters can increase their voting power by up to six times. The increased lock period will be succeeded by the voting period. For example, if a voter decides to increase their voting power by two, their lock period following the voting period will be doubled.

<table><thead><tr><th width="223" align="center">Lock Period</th><th width="162.66666666666666" align="center">Vote Multiplier</th></tr></thead><tbody><tr><td align="center">0.1 (no lock period)</td><td align="center">0.1</td></tr><tr><td align="center">1 (no lock period)</td><td align="center">1</td></tr><tr><td align="center">2</td><td align="center">28</td></tr><tr><td align="center">3</td><td align="center">56</td></tr><tr><td align="center">4</td><td align="center">112</td></tr><tr><td align="center">5</td><td align="center">224</td></tr><tr><td align="center">6</td><td align="center">448</td></tr></tbody></table>

### Balance

To unlock coins used for endorsement and voting which are immediately locked, users need to access the “Profile” page. On the “Profile” page, users can check their balance as well as their governance participation history.&#x20;

To unlock their votes, voters need to click the “Unlock” button under Delegation Status. By clicking this button, voters request the `remove_vote` function to the Bifrost governance system. After the lock period, voters can claim their coins used for voting. Even if `remove_vote` is not requested, unlock will begin automatically after the end of the referendum voting period. However, if `remove_vote` is not requested, the balance will not be transferred to claimable BFC.

## Voting System

In order to alleviate the problem of poor turnout, the Bifrost governance mechanism adopts the Polkadot-based **Adaptive Quorum Biasing (AQB)** protocol instead of the existing quorum-based voting system. This is because the latter requires the participation of a certain number of voters and manifests a number of problems including the following:&#x20;

* Low participation rates due to strict and fixed quorum settings.&#x20;
* Difficulty in setting a specific quorum that is both appropriate and agreeable to all participants.

Conversely, the following are key characteristics of a voting system that is not quorum based:&#x20;

* Participants are rewarded.&#x20;
* However, nonparticipants are penalized.&#x20;

However, this system can lead to malicious actions and disproportionate turnout.

### Voting Mechanics&#x20;

#### Terminology

* **Approve:** number of aye votes (conviction included)&#x20;
* **Against:** number of nay votes (conviction included)&#x20;
* **Turnout:** total number of votes (conviction not included)&#x20;
* **Electorate:** total number of coins issued in the network&#x20;
  * The total number of coins issued in the network refers to the number of BFC in the Bifrost Network.

#### Positive Turnout Bias (PTB)&#x20;

## &#x20;                                           $$\frac{against}{\sqrt{turnout}} < \frac{approve}{\sqrt{electorate}}$$&#x20;

* A referendum will be approved when the majority of voters vote “aye” and there is a low turnout. However, with a high turnout, there should be fewer “aye” votes.&#x20;
* The general public will vote on a PTB basis (Public Proposal).&#x20;

#### Negative Turnout Bias (NTB)

## &#x20;                                            $$\frac{against}{\sqrt{electorate}} < \frac{approve}{\sqrt{turnout}}$$

* A referendum will be rejected when the majority of voters vote “nay” and there is a low turnout. However, with a high turnout, there should be fewer “nay” votes.&#x20;
* All proposals submitted by the council members’ (External Proposal) are based on the NTB model.

#### Example&#x20;

<table><thead><tr><th width="197" align="center">Parameter</th><th width="375" align="center">Value </th></tr></thead><tbody><tr><td align="center">approve</td><td align="center">6000 (1000 * 6) = lock balance * conviction</td></tr><tr><td align="center">against</td><td align="center">10 (100 * 0.1) = lock balance * conviction</td></tr><tr><td align="center">turnout</td><td align="center">1100 (1000 + 100) = approve + against</td></tr><tr><td align="center">electorate</td><td align="center">1M</td></tr><tr><td align="center">result</td><td align="center">0.3 &#x3C; 6 (aye wins)</td></tr></tbody></table>

## &#x20;                                                $$\frac{10}{\sqrt{1100}} < \frac{6000}{\sqrt{1000000}}$$

## &#x20;                                                    $$\frac{10}{{33.166}} < \frac{6000}{\ {1000}}$$

## Governance Flow

1. Holders have to create a “Proposal Hash”, a hash containing the changes.&#x20;
2. Once the “Proposal Hash” is created, the hash creator can either choose to submit a proposal by themself or ask other holders to submit a proposal using the hash. The proposer must deposit or lock up a certain amount of coins into the governance to register a proposal. If the submission is successful, the proposal is publicly registered.&#x20;
3. At the end of every Launch Period, the proposal with the most endorsement will become a referendum and voters will vote either “aye” or “nay” during the voting period.&#x20;
4. At the end of the voting period, the Bifrost governance system will aggregate casted votes to determine whether a referendum or referenda will be approved.&#x20;
5. If a referendum or referenda are approved, the Bifrost network will reflect the changes after the enactment period.

## Council

Council members are in charge of managing the Bifrost Governance. Their role is to cancel malicious referenda, select the technical committee and manage the treasury.&#x20;

In case the council members are unable to participate in every activity, a prime member to represent them is separately selected. The council member who receives the highest number of votes during the council round is selected as a prime member. Members who do not cast votes on council proposals automatically follow the vote of the prime member

## Technical Committee

The technical committee is a committee selected by the council members and is also responsible for managing the Bifrost Governance and preventing unilateral actions of council members. Members of the technical committee have the authority to cancel malicious proposals and proposals created by the council members and to fast-track proposals when necessary.

Members of the technical committee have veto powers to prevent any potential abuses by council members. If even one member exerts veto power, the proposal is nullified and enlisted on the blacklist for a certain period of time. This prevents the submission of relevant proposals. In addition, like council members, members of the technical committee cannot exercise certain authority indefinitely and must possess BFC tokens.

## Treasury

The treasury stores and burns BFC which have been slashed when proposals and referenda are canceled. They also store the slashed BFC of network node operators. The treasury is managed by the council members. The council members will do their best to carefully manage the treasury so as not to lose the trust of community members. Keep in mind that council members are also BFC holders who will not take any actions that negatively affect the Bifrost Network.<br>

## FAQ

1. **I am not familiar with codes. Is there any way I can create proposals without coding knowledge?**\
   \
   You can create proposals without blockchain or coding knowledge. Select “bfcUtility” under “communityProposal”. Then, insert the URL that explains your proposal under proposal "Bytes". We encourage you to use the Bifrost Governance Forum URL.<br>
2. **How can I submit a proposal on the behalf of other voters?**\
   \
   Our governance mechanism allows one to submit proposals on the behalf of other voters or network participants. To submit a proposal on the behalf of other voters, you must know the “Preimage Hash” and all the changes on the “Pallet” and the “Extrinsic”. Click “Submit a Proposal” and insert “Preimage Hash” created by another holder and imply all the changes of the “Pallet” and the “Extrinsic”.


# Security

To ensure the security of all stakeholders of the network, Bifrost implements several lines of defense. Socket contracts and relayers play a major role.

All relayers must sign the message with their private key in every message handling. The Bifrost Network should accept messages of valid relayers by verifying the message signature.

* Every socket contract verifies the signed message to check whether or not the message is from valid relayers.

Relayers and socket contracts perform sanity checks for every Cross-Chain Communication (CCC) message at each stage.

* If an Ethereum transaction related to the CCC job is not executed for a long time, the network identifies the transaction and then runs a corresponding action, such as transaction rollback.
* The network is able to identify the message which falls under abnormal situations (e.g. transaction revert and transaction pending for a long time).


# Tokens & Assets

About Bifrost Network's tokens and assets.&#x20;


# Unified Token

### What is Unified token?

One of the standout features of the Bifrost Network is its commitment to a developer-friendly environment, epitomized by the implementation of the Unified Token (ERC-20 based). This innovative approach consolidates tokens from disparate chains, such as Ethereum’s DAI and BNB Chain’s DAI, under a single token contract. By doing so, it streamlines liquidity management for DApp developers by minimizing the complexities associated with fragmented bridge tokens. For instance, when DAI tokens from Ethereum and BNB Chain are transferred to the Bifrost Network, they are seamlessly integrated into a single Unified DAI token, thereby simplifying asset management and enhancing developer efficiency.

### Contract address

These are the unified token contracts within our network.

#### Mainnet

<table><thead><tr><th width="198">Name</th><th>Address</th></tr></thead><tbody><tr><td>Unified BFC</td><td>0xae172d8c5e428d4b7c70f9e593b207f9dac9bf3e</td></tr><tr><td>Unified BiFi</td><td>0x047938c3ad13c1eb821c8e310b2b6f889b6d0003</td></tr><tr><td>Unified ETH</td><td>0x6c9944674c1d2cf6c4c4999fc7290ba105dcd70e</td></tr><tr><td>Unified BNB</td><td>0xb800eaf843f962dfe5e145a8c9d07a3e70b11d7f</td></tr><tr><td>Unified MATIC</td><td>0x21ad243b81eff53482f6f6e7c76539f2cfc0b734</td></tr><tr><td>Unified USDC</td><td>0x640952e7984f2ecedead8fd97aa618ab1210a21c</td></tr><tr><td>Unified USDT</td><td>0x3ea8654d5755e673599473ab37d92788b5ba12ae</td></tr><tr><td>Unified DAI</td><td>0xcdb9579db96eb5c8298df889d915d0ff668aff2a</td></tr><tr><td>Unified BTCB</td><td>0xd267f821f1b8344b5a63626c8c824697194a173e</td></tr><tr><td>Unified WBTC</td><td>0x7b8fac5f29e101baab33c5f9c39d4f85ba2cc7c1</td></tr><tr><td>Unified SAT</td><td>0x17102ac78a02a98fc78b0c29b7b0506f035a99e5</td></tr><tr><td>Unified WITCH</td><td>0xb1f3a83597bce2ad842c29bd750ae17afc474137</td></tr><tr><td>Unified P2D</td><td>0xaa2e0911ac56c6f8a9c4f0006a8c907d5d180a6a</td></tr><tr><td>Unified EGG</td><td>0x9dd4d64e41ea7fc90acec15b08552172ce94556a</td></tr></tbody></table>

#### Testnet

<table><thead><tr><th width="198">Name</th><th>Address</th></tr></thead><tbody><tr><td>Unified BFC</td><td>0xb0ff18cb2d0f3f51a9c54af862ed98f3caa027a1</td></tr><tr><td>Unified BiFi</td><td>0x8010a873d59719e895e20f15f9906b5a1f399c3a</td></tr><tr><td>Unified ETH</td><td>0xc83eed1bf5464ed5383bc3342b918e08f6815950</td></tr><tr><td>Unified BNB</td><td>0xcd8bf79fa84d551f2465c0a646cabc295d43be5c</td></tr><tr><td>Unified MATIC</td><td>0xad115f901a1af99dc83d055c89641031fd1a50dc</td></tr><tr><td>Unified USDC</td><td>0x28661511cda7119b2185c647f23106a637cc074f</td></tr><tr><td>Unified USDT</td><td>0x815e850cddb2bb8c8afb61266525daffb9add7dc</td></tr><tr><td>Unified DAI</td><td>0x2353859d0c5cd0cb4da701d2aca9f1222ad71110</td></tr><tr><td>Unified BTCB</td><td>0xa4bde980daabdf9861f87ea89d4854a5ff062755</td></tr><tr><td>Unified WBTC</td><td>0xb710c446e2e4e162d734580bd6f13725c345e1f7</td></tr><tr><td>Unified SAT</td><td>0x3325b631cd1b972628f021c3bb776e21290bab21</td></tr><tr><td>Unified WITCH</td><td>0x97c46701a8599df99abb306ce8980b5f57d833fb</td></tr><tr><td>Unified P2D</td><td>0xda007bea12013ee90d5dec4111dba5bd98314f93</td></tr><tr><td>Unified EGG</td><td>0xc53ce1aa929e9e8b7f9587bbee2ab0fb530fe676</td></tr></tbody></table>


# Inflation Model

BFC inflation model lies in motivating participants of the Bifrost Network and expanding the network. Holding BFC without utilizing them comes with an opportunity cost under the current inflation model, leading to BFC dilution over time.

Economic research or from an economic perspective, emphasizes the importance of having an optimal inflation rate to incentivize network participants to foster growth. Lowering the inflation rate may hinder the growth, while increasing the inflation rate could disrupt the model of the token. Since inflation rate is dynamically adjusted by the codes, considering the status of the network, our inflation remains subject to change through governance, rather than permanently fixed.

BFC functions as the native currency of Bifrost and is characterized by its inflationary nature. The inflation rate within the Bifrost network is contingent upon the quantity of tokens staked. As the number of staked tokens varies, the allocation of inflationary rewards to validators and nominators is dynamically adjusted to optimize participation incentives for staking.

{% hint style="info" %}
The inflation rate doesn’t target the token supply; instead, it targets the staked tokens.
{% endhint %}

The dynamic inflation rate can be divided into three segments: minimum, ideal, and maximum. Currently, these segments are set at 7%, 10%, and 13%, respectively. The inflation model incentivizes network participants by selecting one of the three inflation rates based on the current amount of staked tokens.

The rate selection follows the rules below:

* Minimum rate: current staked tokens ≥ expected maximum staked tokens
* Ideal rate: expected minimum staked tokens < current staked tokens < expected maximum staked tokens
* Maximum rate: current staked tokens ≤ expected minimum staked tokens

The minimum rate is applied when the staked tokens exceed expectations, thereby disincentivizing network participants with reduced staking rewards. Conversely, the maximum rate is applied when the staked tokens fall below expectations, thereby incentivizing participants with increased rewards to reach the ideal range.

Establishing an ideal inflation rate and expectations is crucial for motivating network participants and supporting network growth. Reducing the inflation rate may hinder growth, while increasing it could destabilize the token's inflation model. Therefore, the token inflation rate is not fixed indefinitely; it can be adjusted in the future through on-chain governance, depending on the Bifrost ecosystem and tokenomics.

The objective is to align the staked tokens with the ideal staked tokens, ensuring there is sufficient backing of BFC to prevent potential security compromises while maintaining the liquidity of the native token.


# Pockie

How to Connect to the Bifrost Network in Pockie

### Using Pockie

You don’t need to manually add the Bifrost Network in Pockie.

Pockie supports three types of BFC tokens:

&#x20;• Ethereum Network (ERC-20) BFC

&#x20;• Bifrost Mainnet BFC

&#x20;• Testnet BFC

By default, tokens from all networks are displayed. When you select a specific network, only the tokens from that network will be visible.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FhVSz4SJ32yCA26U3ottE%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2025_03_19_%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB_10_47_38.png?alt=media&amp;token=4d3a9928-3b75-4a6a-b36c-a11a293a0e80" alt=""><figcaption></figcaption></figure>

**< Download Mobile App >**

[AppStore](https://apps.apple.com/us/app/pockie-wallet-crypto-wallet/id6448715234)

[GooglePlayStore](https://play.google.com/store/apps/details?id=com.pilab.pockie)

**< Download Browser Extension >**

[Chrome](https://chromewebstore.google.com/detail/pockie-wallet/dmjmllblpcbmniokccdoaiahcdajdjof)


# MetaMask

How to Add the BIFROST Network on MetaMask

{% hint style="info" %}
💡 RPC Information

1. Network Name: Bifrost Network
2. RPC URL: <https://public-01.mainnet.bifrostnetwork.com/rpc>
3. Chain ID: 3068
4. Currency symbol: BFC
5. Block explorer URL (Optional): <https://explorer.mainnet.bifrostnetwork.com/>
   {% endhint %}

Once you complete the following steps, you will see BFC in your wallet. If you experience any difficulty, please contact us through [Discord](https://discord.com/invite/bifrostcit).

#### How to Manually Add the Bifrost Network

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FEbzH1dhuTTF4IC1cxyY2%2FGIF_AddNetwork.gif?alt=media&amp;token=813f1ba5-c6bd-48b4-925e-5cc342f31594" alt=""><figcaption></figcaption></figure>

1. Click “My accounts” on the top right corner of the page. Then click “Settings”.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FmvYXqM20dikboRRx1IIU%2FFrame%2047%20(3).jpg?alt=media&amp;token=e8fa1872-e78c-4e1f-85d6-bb3cde6587aa" alt=""><figcaption></figcaption></figure>

2. Under “Settings”, scroll down to click “Networks”.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FSK9eyQUhxgIQw1fa0jXM%2FFrame%2040.jpg?alt=media&amp;token=1bd9f078-0e0f-44ec-b25b-ba8dd97a5f48" alt=""><figcaption></figcaption></figure>

3. Click “Add network”.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F9LogyZmj49d99fmg4IsX%2FFrame%2042.jpg?alt=media&amp;token=4a91eb20-464c-4bbd-bf6d-b81ed1b738bb" alt=""><figcaption></figcaption></figure>

4. Once you are directed to a new page, click “Add a network manually”.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FAs7IbFKiJpyiH2wCAO5j%2FFrame%2043.jpg?alt=media&amp;token=7d87ca07-899f-434d-b8ee-e80ea9e26cbf" alt=""><figcaption></figcaption></figure>

5. Type in the correct “[Network name”, “New RPC URL”, “Chain ID”, “Currency symbol”, and “Block explorer URL](https://docs.thebifrost.io/bifrost-network/add-network/metamask)”.

{% hint style="info" %}
💡 RPC Information

1. Network Name: Bifrost Network
2. RPC URL: <https://public-01.mainnet.bifrostnetwork.com/rpc>
3. Chain ID: 3068
4. Currency symbol: BFC
5. Block explorer URL (Optional): <https://explorer.mainnet.bifrostnetwork.com/>
   {% endhint %}

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2Fm8gJNdyHqRekOkQAM8zw%2FFrame%2048%20(1).jpg?alt=media&amp;token=e4722b43-429c-4cb2-af71-2d2fd9a889d6" alt=""><figcaption></figcaption></figure>

6. Success! The Bifrost Network has been added to MetaMask!


# Bridge Guide

### The BIFROST Bridge

#### What is a bridge?

A bridge is a service that allows the transfer of information and assets existing on different blockchain networks. An example of when and how a bridge would be used is as follows. If a user has USDC on Ethereum and wants to use this asset on the BIFROST Network, the user would use a bridge to transfer USDC from Ethereum to BIFROST. All blockchain networks, such as Ethereum and Polygon, have their own set of rules and consensus mechanisms. Bridges are a solution to connect these two economically and technologically different networks in order to broaden cryptocurrency usage and enhance interoperability.

#### Why do we need a bridge?

As mentioned previously, all blockchains have independent environments, each with its rules and consensus mechanisms. As such, each chain on its own cannot communicate with another, and tokens minted on one network cannot move to another network freely. A bridge is used to overcome this problem of interoperability and allows assets to move freely across chains. In addition to the above, the BIFROST Bridge acts as a core infrastructure in forming a multichain ecosystem by providing the benefits listed below.

* Support for major networks, such as BIFROST, BNB Chain, Polygon, and Ethereum
* A low service fee of 0.005%
* Fast execution speed, with a maximum of 15 minutes
* High compatibility with BIFROST Network Staking, BiFi, BiFi X, Pockie and other BIFROST DApps
* Solving the problem of liquidity fragmentation

#### Supported networks and tokens

Here is the list of networks and assets currently supported by the BIFROST Bridge. This list will grow as more networks and tokens are added.

| Network   | Assets                                                                                                |
| --------- | ----------------------------------------------------------------------------------------------------- |
| Bifrost   | BFC, BiFi, ETH, USDC, USDT, DAI, BtcUSD, BTCB, WBTC, cbBTC, BTC, BNB, POL, CORE, P2D, WITCH, SAT, EGG |
| Bitcoin   | BTC                                                                                                   |
| Ethereum  | BFC, BiFi, ETH, USDC, USDT, WBTC, WITCH, SAT, EGG                                                     |
| Base      | ETH, DAI, USDC, BtcUSD, cbBTC                                                                         |
| Arbitrum  | ETH, USDC, USDT, WBTC                                                                                 |
| Core      | CORE, BtcUSD, BTCB, WBTC                                                                              |
| BNB Chain | BNB, USDC, USDT, BtcUSD, BTCB, P2D                                                                    |
| Polygon   | POL, USDC, WBTC                                                                                       |
| Oasys     | BFC, BtcUSD                                                                                           |


# Depositing to the Bifrost Network

Depositing to the BIFROST Network

### Making a deposit with the Bifrost Network

The Deposit feature allows you to bring assets from other networks to the Bifrost Network. This guide will walk you through how to bridge an Ethereum network-based BFC to a Bifrost Network-based BFC.

**Step 1) Connect your wallet**

1. Access the Bifrost Bridge page (<https://www.bifrostnetwork.com/bridge>)
2. Click the wallet icon in the top right corner to connect your wallet.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F5Sk4zTNTtGFX7pJWQsPy%2FUntitled%20(10).png?alt=media&amp;token=fbed13ac-5264-4222-bed7-cda35cbdcd0c" alt=""><figcaption></figcaption></figure>

**Step 2) Select a network and token**

1. Select which network are you doing a deposit from.
2. Select a token. Different networks support different types of tokens. You can see the supported networks and tokens page.
3. Enter the amount of tokens to deposit. If the amount condition is not met, the bridge may not be able to run. If the execute button is not enabled, you will need to take a look at the minimum/maximum amount. Please check the minimum amount to deposit and the maximum amount to deposit to be able to proceed. (The maximum deposit amount may vary depending on liquidity conditions).

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F6NKkyTpJCl9QoMnwSlC9%2FUntitled%20(11).png?alt=media&amp;token=8618b080-7f7c-4b14-aa3a-bb476fdfb866" alt=""><figcaption></figcaption></figure>

**Step 3) Launch the bridge**

1. Click the Approve button to agree to grant access for the token to be sent.
2. Click the “Deposit” button to run the bridge.
3. When the connected wallet opens, check the estimated gas cost and confirm.
4. Complete the bridge transaction. The time to bridge can fluctuate depending on network congestion.

**Step 4) Check the bridge transaction execution history.**

1. At the top of the page where you launched the bridge, under the “Use” tab, click “Explorer” (<https://explorer.mainnet.bifrostnetwork.com/>).

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F0Zzz1bY4EUgSy19M90tR%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-06%2015.50.53.png?alt=media&amp;token=2ec3bd3b-e3ae-40d9-80d6-fb24d884fd03" alt=""><figcaption></figcaption></figure>


# Withdrawing to another network

Withdrawing to another network

### Withdrawing to other networks

The “Withdraw” feature allows you to move assets on the Bifrost Network to another network. This guide will walk you through how to bridge a Bifrost Network-based BFC to an Ethereum Network-based BFC.

{% hint style="info" %}
If you are sending BFC to a centralised exchange (CEX), please make sure that the exchange supports the Bifrost Network. For example, if you send A Network-based tokens directly to an exchange that does not support A Network, you will lose your tokens, and neither the Foundation nor the exchange will be responsible for lost tokens.
{% endhint %}

**Step 1) Connect your wallet and set up your network**

1. Access the Bifrost Bridge page (<https://www.bifrostnetwork.com/bridge>)
2. Click the top-right wallet icon to connect your wallet.

If the wallet you connect does not see the Bifrost Network, follow these steps: Settings - Networks - Search for and select Bifrost Network in the network search bar to connect.

If it is not found, enter the following information on the Add network page and save it:

{% hint style="info" %}
Network Name: Bifrost Network

RPC URL: <https://public-01.mainnet.bifrostnetwork.com/rpc>

Chain ID: 3068

Currency symbol: BFC

Block explorer URL (Optional): <https://explorer.mainnet.bifrostnetwork.com/>
{% endhint %}

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FF7swS2mGpeMV1sXR3Uzd%2FWithdrawing%20Step1-4.png?alt=media&amp;token=a24a131c-e23c-4dd2-bc87-29ac7fe347e7" alt=""><figcaption></figcaption></figure>

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2Fp8Vw263sABWH69UAa4ZD%2FWithdrawing%20Step1-5.png?alt=media&amp;token=cd3673e2-88f5-473b-81f4-aab2b92215f2" alt=""><figcaption></figcaption></figure>

**Step 2) Select a network and token**

1. On the Withdraw tab, select the network you want to withdraw to.
2. Select a token.
3. Enter the amount of tokens to withdraw. If the amount condition is not met, the bridge may not be able to run. If the execute button is not enabled, you will need to take a look at the minimum/maximum quantity. Please check the minimum amount to withdraw and the maximum amount to withdraw to be able to proceed. (The maximum withdrawal amount may fluctuate depending on liquidity conditions).

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FZGK8vCeFjQmVr9qndoAw%2FUntitled%20(13).png?alt=media&amp;token=e4031c64-38a8-42a3-8f9c-a4bb1e13f049" alt=""><figcaption></figcaption></figure>

**Step 3) Launch the bridge**

1. Click the Approve button to agree to grant access to the token to be sent.
2. Click the “Withdraw” button to run the bridge.
3. When the connected wallet opens, check the estimated gas cost and confirm.
4. Complete the bridge transaction. The time to bridge can fluctuate depending on network congestion.

**Step 4) Check the bridge transaction execution history.**

1. At the top of the page where you launched the bridge, under the “Use” tab, click “Explorer” (<https://explorer.mainnet.bifrostnetwork.com/>).

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FyMQxTov2QzaD7zSAtq1d%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-06%2015.50.53.png?alt=media&amp;token=5f81e085-c50e-48aa-9721-74d2f172cd60" alt=""><figcaption></figcaption></figure>


# Glossary

### Glossary

<mark style="color:purple;">**Minimum amount to deposit**</mark>

The minimum amount of assets to execute bridging to the Bifrost Network

<mark style="color:purple;">**Maximum amount to deposit**</mark>

The current maximum amount of bridgeable assets

<mark style="color:purple;">**Minimum amount to withdraw**</mark>

The minimum amount of assets to execute bridging out of the Bifrost Network

<mark style="color:purple;">**Maximum amount to withdraw**</mark>

The current maximum amount of bridgeable assets.

<mark style="color:purple;">**Service fee**</mark>

The fee that will be paid for the bridge transaction. The Bifrost Bridge currently charges a minimum of 0.005% to a maximum of 0.05% as a service fee. This fee varies depending on the network conditions and is subject to change.

<mark style="color:purple;">**Time to transfer**</mark>

The time it takes for an asset to be bridged over. The amount of time for bridging depends on network conditions.


# Staking Guide

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><mark style="color:blue;">Stake BFC</mark></td><td></td><td></td><td><a href="/bifrost-network/staking/staking-guide/stake-bfc">Stake BFC</a></td></tr><tr><td><mark style="color:blue;">Unstake BFC</mark></td><td></td><td></td><td><a href="/bifrost-network/staking/staking-guide/unstake-bfc">Unstake BFC</a></td></tr></tbody></table>


# Stake BFC

Stake BFC on the Bifrost Network Page

1. Go to the Bifrost staking page (<https://www.bifrostnetwork.com/stake>).

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2ForCr65PkiwnUfppp8j8j%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-04%2011.28.39%20(1).png?alt=media&amp;token=4673e23a-bd4e-4eb0-83f7-b888df0ec084" alt=""><figcaption></figcaption></figure>

2. If you click on the “Stake to a Validator” button it will take you to the “My Staking Status” section.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FtnxLhuBNz2zeM6XQrYFM%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-04%2011.29.12.png?alt=media&amp;token=c38c85cd-0b73-4415-96bb-558a096d7b7f" alt=""><figcaption></figcaption></figure>

3. In “My Staking Status” section, click “Connect wallet” to connect your wallet.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FKBBeL0FilIQoGn3x5aOB%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-04%2014.58.22.png?alt=media&amp;token=b17c8ca8-df0c-4275-8393-94c8a2e3cbe5" alt=""><figcaption></figcaption></figure>

4. By scrolling down you can check the “All Validators” section information.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FcBYspyem9Yx7Sc1hYnBR%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-04%2014.59.50.png?alt=media&amp;token=7d4ce502-dcb9-4244-9747-6801b34465ee" alt=""><figcaption></figcaption></figure>

5. Select a validator, enter the amount of BFC you want to stake and click the “Continue” button.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FShe54fj5xstEjJ8EnQUY%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-04%2015.08.17.png?alt=media&amp;token=d701a249-8570-48ca-8c29-d3c53b0ac7a2" alt=""><figcaption></figcaption></figure>

6. Confirm in your wallet to complete your staking.


# Unstake BFC

Learn How to Unstake BFC

1. Go to the Bifrost staking page (<https://www.bifrostnetwork.com/stake>).

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FxbsiysIx7sZaMvZwh49b%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-04%2011.28.39%20(1).png?alt=media&amp;token=93af31de-98d2-4438-a229-f940d8ae5a83" alt=""><figcaption></figcaption></figure>

2. Connect your wallet, select the assets that you want to unstake in the “All Validators” section, enter the amount of tokens, and click “Continue”.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2F6VilQYOaIRZztSM4UTCN%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-04%2015.08.17.png?alt=media&amp;token=36db115b-3b3d-40fc-a2c9-4e881889dec5" alt=""><figcaption></figcaption></figure>

3. Once you confirm in your wallet, the following pop-up message will be displayed. Click “Confirm” to complete unstaking.

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FyETwSisMpzgBtZQRhIdc%2FUntitled%20(3).png?alt=media&amp;token=51fdc26e-d6fc-433e-8955-9547ba19acaa" alt=""><figcaption></figcaption></figure>

4. You can check your unstaking request history in the “My Staking Status” section.
5. You can receive rewards only after the unstaking period has elapsed. You can check this period of time in the “My Staking Status” section. Once your cancellation process has been completed, you may request a withdrawal at any time. (The duration of the cancellation may vary depending on the moment of your request)

If you have any questions about BFC staking, please reach out to us through [Discord](https://discord.com/invite/bifrostcity).


# Glossary


# All Validators

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FDNiXLCGkpUMwpdAyHNmy%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202023-07-04%2014.59.50.png?alt=media&amp;token=aacb0991-ab39-4dc2-8a3f-f6d8cee170fd" alt=""><figcaption></figcaption></figure>

1. Search by Name/Address: You can search by entering the name of the validator or the address of the controller.
2. Types: The search can be distinguished between “Full node” or “Basic node” types.
3. Name: Displays the name of the validator.
4. Address: Displays the controller address of the validator.
5. Staked: Displays the BFC stake of this validator. This represents the amount of self-bonding the validator has deposited into the network and the total amount of BFC nominated to them.
6. Productivity: Its an indicator of whether a validator is reliably generating blocks during that round correctly. For example if productivity is shown as 100%, it means that the validator node is generating blocks with 100% efficiency and no failures.
7. Commission: Commission refers to the fee that a validator charges to nominators who stake to them in exchange for delegation. Commission rates vary by validator.
8. EYR: Estimated annualised yield.
9. Staking: Click the “Staking” button to stake to the corresponding validator. If you are currently staking, an unstaking button will appear instead.


# My Staking Status

<figure><img src="https://3596680066-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FISx9P4kYm2Zecfailc61%2Fuploads%2FBSNuX5tSzw6VZPOX6Iro%2FUntitled%20(15).png?alt=media&amp;token=7ea5065e-58e9-4af8-928a-f40c28b285a7" alt=""><figcaption></figcaption></figure>

1. Staked balance: Displays the balance of tokens being staked.
2. Estimated Yearly Return: Displays the estimated annual return.
3. Average APY: Displays the average annual percentage yield.
4. Remaining Unstaking Period: Displays the remaining period before unstaking is complete.


