> ## Documentation Index
> Fetch the complete documentation index at: https://docs.berachain.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Become a Validator

> Register and activate a validator: beacond setup, deposit transaction, BeaconDeposit contract, operator and withdrawal address.

This guide walks you through the process of becoming a validator node on Berachain.

## Requirements

* A fully-synced full node — See [Quickstart](/nodes/operations/quickstart)
* [Foundry](https://book.getfoundry.sh/getting-started/installation)
* Berachain Wallet with a minimum of 250,000 `$BERA` (or the current minimum to meet the Active Set) + gas to process the transaction

If you haven't already, please read through the [Validator Lifecycle](/nodes/architecture/validator-lifecycle) overview that explains the lifecycle of a validator.

**Your goal** is to deposit your stake and establish a connection between your **validator identity** on the consensus layer, your **operator identity** on the execution layer, and the **withdrawal address** where your stake is returned when you stop being a validator.

If you would like to test this out locally, consult the guide to a [local Kurtosis-based devnet](/nodes/guides/local-devnet-kurtosis), which includes instructions on testing deposits.

## Step 1: Check beacond and set up environment

A point of reassurance about `beacond`: it *cannot* transact on your behalf on either the execution or consensus layers. By invoking `beacond` on the command line you are not playing with TNT strapped to your stake.

You can ask `beacond help` for a list of commands, then `beacond help command` for help on a certain command. Have a look at `beacond help deposit create-validator`.

`beacond` wants a `--home` option specifying the data directory. This should be provided every time you use this command. In this guide, we will use an environment variable and refer to it with `--home $BEACOND_HOME`.

Below is an example of setting up and verifying the environment. It's okay, even encouraged, that when depositing your stake you do so on your validator's full node, so that you have the CometBFT private keys available to you.

```bash theme={null}
export BEACOND_HOME=/full/path/to/beacond-data;
export RPC_URL="https://rpc.berachain.com"; # mainnet
export DEPOSIT_ADDR="0x4242424242424242424242424242424242424242"; # mainnet
export COMETBFT_PUB_KEY="<YOUR_COMETBFT_PUB_KEY>";
export OPERATOR_ADDRESS="<YOUR_OPERATOR_ADDRESS>";
export WITHDRAW_ADDRESS="<YOUR_WITHDRAW_ADDRESS>";

alias beacond="/path/to/beacond --home $BEACOND_HOME";
beacond genesis validator-root $BEACOND_HOME/config/genesis.json;

# [Expected Output - MUST BE THIS EXACTLY]
# DO NOT PROCEED UNLESS THIS OUTPUT MATCHES
# 0xdf609e3b062842c6425ff716aec2d2092c46455d9b2e1a2c9e32c6ba63ff0bda

export GENESIS_ROOT=0xdf609e3b062842c6425ff716aec2d2092c46455d9b2e1a2c9e32c6ba63ff0bda # mainnet
```

The `0xdf6..0bda` hash output confirms that you have the right mainnet genesis file.

<Warning>
  If you sign a deposit without using the above genesis root, **the deposit will fail and the funds
  will be burnt**.
</Warning>

* **BEACOND\_HOME**: The path to your beacond data directory.
* **RPC\_URL**: The URL of the RPC endpoint you are using. You can use your own if you want.
* **DEPOSIT\_ADDR**: The address of the deposit contract.
* **COMETBFT\_PUB\_KEY**: The public key of your validator from CometBFT (see below).
* **OPERATOR\_ADDRESS**: The address of the ETH account (EOA) that will become your **operator address** on the execution layer. This is used to interact with contracts such as [BeraChef](/build/getting-started/deployed-contracts).
* **WITHDRAW\_ADDRESS**: The address where your deposit stake is returned when you stop being a validator (state 'Exited' on the [lifecycle](/nodes/architecture/validator-lifecycle)). This can be an address of your choice, or if you are staking money from investors, they will require a specific address.

Your **CometBFT identity** was created by beacond when you did `beacond init`, and is held in the `priv_validator_key.json` file. You can view the corresponding public key for this identity with `beacond deposit validator-keys`:

```bash theme={null}
beacond deposit validator-keys;

# [Example Output]:
# ...
# Eth/Beacon Pubkey (Compressed 48-byte Hex):
# 0x9308360bb1e8c237c2a4b6734782426e6e42bc7a43008ba5e3d9f3c70143227ea1fb2a08b21cbbedf87cebf27e81669d
```

This is your **beacon chain public key**, and in this tutorial is placed in the `COMETBFT_PUB_KEY` environment variable.

## Step 2 - Prepare registration transaction

The first registration transaction is the most important. It establishes the association between your validator key and your presence in the consensus layer. **Mistakes in this step can result in a permanent loss of funds.**

1. **Set up and fund your funding account on Berachain.** You should be equipped so that you can use MetaMask or `cast` to send transactions from the funding account.

2. **Confirm your CometBFT identity has not been used before.** If your validator has exited the active set or failed a deposit transaction, you will need to create a new identity. Check for previous use of your identity with the following command. If this returns non-zero, start over with a new beacond identity (as described in the Quickstart).

```bash theme={null}
cast call $DEPOSIT_ADDR 'getOperator(bytes)' $COMETBFT_PUB_KEY -r $RPC_URL;
```

<Warning>
  Do not change any parameters of your deposit transaction before sending them. Calculate the
  signature for the parameters *and deposit amount* you are going to send to the deposit contract.
  If you change anything after calculating the signature, **the deposit will fail and the funds will
  be burnt**.
</Warning>

3. **Have `beacond` calculate the parameters** for the transaction you will send with `beacond deposit create-validator` which takes:
   * **withdrawal-addr**: as described in Step 1
   * **stake-amount**: the initial stake amount (as GWei). It is strongly recommended to use the minimum — 10,000 `$BERA`.
   * **genesis-root**: as confirmed in Step 1.

```bash theme={null}
STAKE_AMOUNT_ETH="10000";
STAKE_AMOUNT_GWEI="${STAKE_AMOUNT_ETH}000000000"

beacond deposit create-validator \
  $WITHDRAW_ADDRESS              \
  $STAKE_AMOUNT_GWEI             \
  -g $GENESIS_ROOT;

# [Expected Output]:
#  "pubkey": "<COMETBFT_PUB_KEY>",
#  "credentials": "0x010000000000000000000000<WITHDRAW_ADDRESS>",
#  "amount": "0x9184e72a000",
#  "signature": "0x94349ab1...fb4b1d6",

DEPOSIT_SIGNATURE="0x9434...";  # from the above output
WITHDRAW_CREDENTIAL="0x01000..."; # from the above output
```

The credentials should contain the withdrawal address verbatim, and the public key confirms the public key matching the private key used to generate the signature.

4. Finally, **verify that beacond will accept this signature** with `beacond deposit validate` which should produce no error message.

```bash theme={null}
beacond deposit validate   \
  $COMETBFT_PUB_KEY        \
  $WITHDRAW_CREDENTIAL     \
  $STAKE_AMOUNT_GWEI       \
  $DEPOSIT_SIGNATURE       \
  -g $GENESIS_ROOT;
echo $?;

# [Expected Output]:
# 0
```

You now have everything needed to deposit the initial 10,000 `$BERA`.

## Step 3 - Send registration transaction

You will now send the above transaction onto the chain by calling the `deposit` function on the [BeaconDeposit](/build/getting-started/deployed-contracts) contract (`0x4242424242424242424242424242424242424242`):

```solidity theme={null}
function deposit(
    bytes calldata pubkey,
    bytes calldata credentials,
    bytes calldata signature,
    address operator
)
    external
    payable
```

* **pubkey** is the CometBFT public key.
* **credentials** and **signature** are the values generated by `beacond` in the previous step.
* **operator** is the EOA address you created in the "Preliminaries" step.

<CodeGroup>
  ```bash Non-Ledger theme={null}
  cast send $DEPOSIT_ADDR \
  'deposit(bytes,bytes,bytes,address)' \
  "$COMETBFT_PUB_KEY"                  \
  "$WITHDRAW_CREDENTIAL"               \
  "$DEPOSIT_SIGNATURE"                 \
  "$OPERATOR_ADDRESS"                  \
  --private-key $PK                    \
  --value "${STAKE_AMOUNT_ETH}ether"   \
  -r $RPC_URL;
  ```

  ```bash Ledger theme={null}
  cast send $DEPOSIT_ADDR              \
  'deposit(bytes,bytes,bytes,address)' \
  "$COMETBFT_PUB_KEY"                  \
  "$WITHDRAW_CREDENTIAL"               \
  "$DEPOSIT_SIGNATURE"                 \
  "$OPERATOR_ADDRESS"                  \
  --ledger                             \
  --value "${STAKE_AMOUNT_ETH}ether"   \
  -r $RPC_URL;
  ```
</CodeGroup>

## Step 4 - Confirm successful registration

The following traits denote a successful registration:

1. The deposit contract tx was successful (check block explorer or observe the cast command's output).
2. The balance in the funding account (wallet that sent the deposit contract tx) decreased by the 10,000 `$BERA`.
3. **Most importantly,** the validator's public key is present in the beacon state. The beacon state (available from your node's beacon API at `curl http://localhost:3500/eth/v1/beacon/states/head/validators | jq .data`) should show your validator's public key, likely at the end of the list.

<Info>
  The validator registration is reflected in the Beacon Chain 2 blocks after the deposit contract
  transaction is processed. The beacon API must be enabled on your node (in `app.toml`:
  `[beacon-kit.node-api]`).
</Info>

## Step 5 - Activation or top-up

Having completed the registration, you can now deposit additional `$BERA`. The floor for becoming a validator is **250,000 `$BERA`**, and you must be among the top **69** validators, ordered by `$BERA` staked.

These subsequent deposits are done by calling the same `deposit` function, with only the **public key** required; the other elements may be zero, but must still be the right length.

When your validator passes the threshold necessary to become active, it passes into the **Activation** part of the lifecycle. At the conclusion of the **second epoch** after you pass the threshold — in other words, no sooner than 13 minutes — you become eligible for minting blocks.

<CodeGroup>
  ```bash Non-Ledger theme={null}
  STAKE_AMOUNT_ETH=240000;

  cast send "0x4242424242424242424242424242424242424242" \
  'deposit(bytes,bytes,bytes,address)' \
  "$COMETBFT_PUB_KEY" \
  "0x0000000000000000000000000000000000000000000000000000000000000000" \
  "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" \
  "0x0000000000000000000000000000000000000000" \
  --private-key $PK                    \
  --value "${STAKE_AMOUNT_ETH}ether" \
  -r $RPC_URL;

  ```

  ```bash Ledger theme={null}
  STAKE_AMOUNT_ETH=240000;

  cast send "0x4242424242424242424242424242424242424242" \
  'deposit(bytes,bytes,bytes,address)' \
  "$COMETBFT_PUB_KEY" \
  "0x0000000000000000000000000000000000000000000000000000000000000000" \
  "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" \
  "0x0000000000000000000000000000000000000000" \
  --ledger \
  --value "${STAKE_AMOUNT_ETH}ether" \
  -r $RPC_URL;
  ```
</CodeGroup>

## Post-activation checks

After 2+ epochs after your activation deposit, do the following checks:

1. Run `beacond status`. Verify that the voting power is equal to the effective balance. If voting power is 0, the node is NOT active.
2. Your operator address received `$BGT` when it produces blocks (this will take a few hours).
3. The Comet API on the node will confirm your validator's presence in the set. Look for your validator's public key in the list of validators:

```bash theme={null}
curl http://localhost:26657/validators?page=1&per_page=100 | jq .

# [Example Output]:
# {
#   "jsonrpc": "2.0",
#   "id": -1,
#   "result": {
#     "block_height": "477021",
#     "validators": [
#       {
#         "address": "5951C4349AB792BFB3A63956512663CC3B733D6E",
#         "pub_key": {
#           "type": "cometbft/PubKeyBls12_381",
#           "value": "A/1TcQt1whFb0KrBKLc..."
#         },
#         "voting_power": "10000000000000000",
#         "proposer_priority": "12250000000000000"
#       },
#       ...
#     ],
#     "count": "69",
#     "total": "69"
# }
```

## Steps after becoming a validator

### Step 1 - Add to default validator list

Make a PR to the following GitHub repository to add your validator to the validator list on the Berachain Hub.

[https://github.com/berachain/metadata](https://github.com/berachain/metadata)

If you have a logo you'd like us to use, attach it to the pull request according to the instructions in [CONTRIBUTING](https://github.com/berachain/metadata/blob/main/CONTRIBUTING.md).

### Step 2 - Send Berachain team wallet addresses

Reach out to the Berachain validator relations team with your validator's CometBFT public keys to help find you if your node begins having trouble. If you aren't known to the validator relations team, speak up on the `#node-support` channel on Discord.

Send the output of `beacond deposit validator-keys`.
