StakeWise Operator is a service that StakeWise Vault operators must run. It is responsible for performing the following tasks:
The operator periodically checks whether Vault has accumulated enough assets for registering new validator(s) and sends a registration transaction to the Vault.
The validator registration process consists of the following steps:
- Check whether Vault has accumulated enough assets to register a validator (e.g., 32 ETH for Ethereum)
- Get the next free validator public key from the deposit data file attached to the operator. The validators are registered in the same order as specified in the deposit data file.
- Obtain BLS signature for exit message using local keystores or remote signer.
- Share the exit signature of the validator with StakeWise Oracles:
- Using Shamir's secret sharing, split validator's BLS signature. The number of shares is equal to the number of oracles.
- Encrypt exit signatures with oracles' public keys.
- Send encrypted exit signatures to all the oracles and receive registration signatures from them.
- Send transaction to Vault contract to register the validator.
Exit signatures from the previous section can become invalid if the oracles' set changes. For example, if oracles' private key gets compromised, the DAO will have to propose an update of the oracles set that will trigger exit signature rotation. The operator periodically checks active validators of the Vault and if some exit signatures become outdated, the operator will submit a signature update transaction to the Vault.
The oracles periodically submit consensus rewards of all the vaults to the Keeper contract.
By default, every vault pulls these updates on the user interaction with the vault (deposit, withdraw, etc.), but it
also can be done by the vault operator by passing the --harvest-vault
flag to the start
command. Harvesting vault
rewards simplifies calls to the vault contracts, e.g., you don't need to sync rewards before calling deposit.
Any execution client that supports ETH Execution API specification can be used:
- Nethermind (Ethereum, Gnosis)
- Besu (Ethereum)
- Erigon (Ethereum, Gnosis)
- Geth (Ethereum)
Any consensus client that supports ETH Beacon Node API specification can be used:
- Lighthouse (Ethereum, Gnosis)
- Nimbus (Ethereum, Gnosis)
- Prysm (Ethereum)
- Teku (Ethereum, Gnosis)
- Lodestar (Ethereum, Gnosis)
You must have a deployed Vault. You can create a new Vault or use an existing one. To create a new Vault:
- Go to Operate page.
- Connect with your wallet in upper right corner, then click on "Create Vault".
- Process vault setup step by step.
- Once vault is deployed go to its page.
You can find the vault address either in the URL bar or in the "Contract address" field by scrolling to the "Details" at the bottom of the page. The vault address is used in the following sections.
Operator Service can be run via a binary, docker image, deployed on a Kubernetes cluster using the Operator Helm Chart, or built from source. Decide on your preferred method and follow the respective instructions below.
Head to the releases page to find the latest version of Operator Service. Identify the binary file specific to your node hardware, download and decompress it.
You will execute Operator Service commands from within the v3-operator
folder using the below format (note that the
use of flags is optional):
./operator COMMAND --flagA=123 --flagB=xyz
Head to Usage to launch your operator service.
To install a binary for the latest release, run:
curl -sSfL https://raw.githubusercontent.com/stakewise/v3-operator/master/scripts/install.sh | sh -s
The binary will be installed inside the ~/bin directory. Add the binary to your path:
export PATH=$PATH:~/bin
If you want to install a specific version to a custom location, run:
curl -sSfL https://raw.githubusercontent.com/stakewise/v3-operator/master/scripts/install.sh | sh -s -- -b <custom_location> vX.X.X
You will execute Operator Service commands using the below format (note that the use of flags is optional):
operator COMMAND --flagA=123 --flagB=xyz
Head to Usage to launch your operator service.
Pull the latest docker operator docker image:
docker pull europe-west4-docker.pkg.dev/stakewiselabs/public/v3-operator:v2.1.5
You can also build the docker image from source by cloning this repo and executing the following command from within
the v3-operator
folder:
docker build --pull -t europe-west4-docker.pkg.dev/stakewiselabs/public/v3-operator:v2.1.5 .
You will execute Operator Service commands using the format below (note the use of flags are optional):
docker run --rm -ti \
-u $(id -u):$(id -g) \
-v ~/.stakewise/:/data \
europe-west4-docker.pkg.dev/stakewiselabs/public/v3-operator:v2.1.5 \
src/main.py COMMAND \
--flagA=123 \
--flagB=xyz
Head to Usage to launch your operator service.
Build requirements:
Clone this repo and install dependencies by executing the following command from within the v3-operator
folder:
poetry install --only main
You will execute Operator Service commands from within the v3-operator
folder using the below format (note that the
use of flags is optional):
PYTHONPATH=. poetry run python src/main.py COMMAND --flagA=123 --flagB=xyz
Head to Usage to launch your operator service.
A separate guide runs through the set-up of Operator Service via Kubernetes, designed to run large numbers of validators (up to 10,000). Visit the Kubernetes setup for more details.
In order to run Operator Service, you must first create keystores and deposit data file for your Vault's validators, and set up a hot wallet for Operator Service to handle validator registrations.
Operator Service has in-built functionality to generate all of the above, or you are free to use your preferred methods of generating keystores and deposit data file, such as via Wagyu Keygen, and your preferred tool for generating the hot wallet, such as MetaMask or MyEtherWallet.
Note, the deposit data file must be created using the Vault contract as the withdrawal address. You can find the Vault address either via the URL bar of your Vault page or in the "Contract address" field by scrolling to the "Details" section at the bottom of the Vault page.
The below steps walk you through this set-up using Operator Service:
Run the init
command and follow the steps to set up your mnemonic used to derive validator keys. For example, if
running Operator Service from binary, you would use:
./operator init
Enter the network name (mainnet, holesky) [mainnet]:
Enter your vault address: 0x3320a...68
Choose your mnemonic language (chinese_simplified, chinese_traditional, czech, english, italian, korean, portuguese, spanish) [english]:
This is your seed phrase. Write it down and store it safely, it is the ONLY way to recover your validator keys.
pumpkin anxiety private salon inquiry ....
Press any key when you have written down your mnemonic.
Please type your mnemonic (separated by spaces) to confirm you have written it down
: pumpkin anxiety private salon inquiry ....
done.
Successfully initialized configuration for vault 0x3320a...68
Next, run the create-keys
command to kickstart the deposit data and validator keystores creation process, making sure
you have your newly created mnemonic to hand:
./operator create-keys
Enter the vault address: 0x3320a...68
Enter the number of the validator keys to generate: 10
Enter the mnemonic for generating the validator keys: pumpkin anxiety private salon inquiry ....
Creating validator keys: [####################################] 10/10
Generating deposit data JSON [####################################] 10/10
Exporting validator keystores [####################################] 10/10
Done. Generated 10 keys for 0x3320a...68 vault.
Keystores saved to /home/user/.stakewise/0x3320a...68/keystores file
Deposit data saved to /home/user/.stakewise/0x3320a...68/keystores/deposit_data.json file
You may not want the operator service to have direct access to the validator keys. Validator keystores do not need to be present directly in the operator. You can check the remote signer or Hashicorp Vault guides on how to run Operator Service with them.
Remember to upload the newly generated validator keys to the validator(s). For that, please follow a guide for your
consensus client. The password for your keystores is located in the password.txt
file in the keystores folder.
Run the create-wallet
command to create your hot wallet using your mnemonic (note, this mnemonic can be the same as
the one used to generate the validator keys, or a new mnemonic if you desire).
./operator create-wallet
Enter the vault address: 0x3320a...68
Enter the mnemonic for generating the wallet: pumpkin anxiety private salon inquiry ...
Done. The wallet and password saved to /home/user/.stakewise/0x3320a...68/wallet directory. The wallet address is: 0x239B...e3Cc
Note, you must send some ETH (xDAI for Gnosis) to the wallet for gas expenses. Each validator registration costs around 0.01 ETH with 30 Gwei gas price. You must keep an eye on your wallet balance, otherwise validators will stop registering if the balance falls too low.
Once you have created your validator keys, deposit data file, and hot wallet, you need to upload the deposit data file to the Vault. This process connects your node to the Vault. Note, if there is more than one node operator in a Vault, you first need to merge all operator deposit data files into a single file (use the merge-deposit-data command). Uploading the deposit data file can be achieved either through the StakeWise UI or via Operator Service and can only be done by the Vault Admin or Keys Manager.
- Connect with your wallet and head to the Operate page.
- Select the Vault you want to upload the deposit data file to.
- In the upper right corner, click on "Settings" and open the "Deposit Data" tab. The "Settings" button is only visible to the Vault Admin or Keys Manager.
- Upload the deposit data file either by dragging and dropping the file, or clicking to choose the file via your file browser.
- Click Save and a transaction will be created to sign using your wallet. The Vault's deposit data file will be uploaded when the transaction is confirmed on the network.
If for some reason uploading deposit data using UI is not an option. You can calculate deposit data Merkle tree root with the following command:
./operator get-validators-root
Enter the vault address: 0xeEFFFD4C23D2E8c845870e273861e7d60Df49663
The validator deposit data Merkle tree root: 0x50437ed72066c1a09ee85978f168ac7c58fbc9cd4beb7962c13e68e7faac26d7
Finally, upload the Merkle tree root to your Vault contract by calling setValidatorsRoot
. Below shows the steps to do
this via Etherscan, but the same can be achieved via CLI if you prefer (
using eth-cli and eth contract:send
for example). Note, the ABI of the
contract can be found here.
- Head to your Vault's contract address page on Etherscan in your browser (e.g. replacing 0x000 with your Vault
contract address:
https://etherscan.io/address/0x000...
). - Select the Contract tab and then Write as Proxy. If you don't have Write As Proxy option, click on the Code tab, then More Options, Is this a Proxy?, Verify, Save. Now you should have Write As Proxy option.
- Connect your wallet to Etherscan (note this must be either the Vault Admin or Keys Manager).
- Find the
setValidatorsRoot
function and click to reveal the drop-down. - Enter your Merkle tree root returned from the command and click Write.
- Confirm the transaction in your wallet to finalize the deposit data upload to your Vault.
You are all set! Now it's time to run the Operator Service.
You are ready to run the Operator Service using the start
command, optionally passing your Vault address and consensus
and execution endpoints as flags.
If you did not use Operator Service to generate hot wallet, you will need to add the following flags:
--hot-wallet-file
- path to the password-protected .txt file containing your hot wallet private key.--hot-wallet-password-file
- path to a .txt file containing the password to open the protected hot wallet private key file.
If you did not use Operator Service to generate validator keys, you will need to add the following flag:
--keystores-dir
- The directory with validator keys in the EIP-2335 standard. The folder must contain either a singlepassword.txt
password file for all the keystores or separate password files for each keystore with the same name as keystore, but ending with.txt
. For example,keystore1.json
,keystore1.txt
, etc.
If you did not use Operator Service to generate deposit data file, or you use combined deposit data file from multiple operators, you will need to add the following flag:
--deposit-data-file
- Path to the deposit data file (Vault directory is default).
You can start the operator service using binary with the following command:
./operator start --vault=0x000... --consensus-endpoints=http://localhost:5052 --execution-endpoints=http://localhost:8545
For docker, you first need to mount the folder containing validator keystores and deposit data file generated
into the docker container. You then need to also include the --data-dir
flag alongside the start
command as per the
below:
docker run --restart on-failure:10 \
-u $(id -u):$(id -g) \
-v ~/.stakewise/:/data \
europe-west4-docker.pkg.dev/stakewiselabs/public/v3-operator:v2.1.5 \
src/main.py start \
--vault=0x3320ad928c20187602a2b2c04eeaa813fa899468 \
--data-dir=/data \
--consensus-endpoints=http://localhost:5052 \
--execution-endpoints=http://localhost:8545
PYTHONPATH=. poetry run python src/main.py start \
--vault=0x000... \
--consensus-endpoints=http://localhost:5052 \
--execution-endpoints=http://localhost:8545
Congratulations, you should now have Operator Service up and running and ready to trigger validator registrations within your Vault!
Operator Service has many different commands that are not mandatory but might come in handy:
- Validators voluntary exit
- Update Vault state (Harvest Vault)
- Add validator keys to Vault
- Merge deposit data files from multiple operators
- Recover validator keystores
- Self report to Rated
You can always add more validator keys to your Vault. For that, you need to generate new validator keys and deposit data as described in Step 2. Create validator keys and upload the deposit data file to your Vault as described in Step 3. Upload deposit data file to Vault. Note, uploading a new deposit data file will overwrite the existing file and consequently overwrite previously un-used validator keys. It can be done at any point, but only by the Vault Admin or Keys Manager.
The validator exits are handled by oracles, but in case you want to force trigger exit your validators, you can run the following command:
./operator validators-exit
Follow the steps, confirming your consensus node endpoint, Vault address, and the validator indexes to exit.
Enter the comma separated list of API endpoints for consensus nodes: https://example.com
Enter your vault address: 0x3320ad928c20187602a2b2c04eeaa813fa899468
Are you sure you want to exit 3 validators with indexes: 513571, 513572, 513861? [y/N]: y
Validators 513571, 513572, 513861 exits successfully initiated
Updating the Vault state distributes the Vault fee to the Vault fee address and updates each staker's position. If an ERC-20 token was chosen during Vault creation, the Vault specific ERC-20 reprices based on the rewards/penalties since the previous update and the Vault fees are distributed in newly minted ERC-20 tokens.
By default, each Vault state gets updated whenever a user interacts with the Vault (deposit, withdraw, etc.), with a
12 hours cooldown. Vault state can also be updated by the Vault operator(s) by passing the --harvest-vault
flag to the
Operator Service start
command. Harvest occurs every 12 hours and the gas fees are paid by the hot wallet linked to
the Operator Service.
Harvesting the Vault rewards simplifies the contract calls to the Vault contract and reduces the gas fees for stakers, for example, the Vault does not need to sync rewards before calling deposit when a user stakes.
You can use the following command to merge deposit data file:
./operator merge-deposit-data
You can recover validator keystores that are active. Make sure there are no validators running with recovered validator keystores and 2 epochs have passed, otherwise you can get slashed. For security purposes, make sure to protect your mnemonic as it can be used to generate your validator keys.
./operator recover
Enter the mnemonic for generating the validator keys: [Your Mnemonic Here]
Enter your vault address: 0x3320ad928c20187602a2b2c04eeaa813fa899468
Enter comma separated list of API endpoints for execution nodes: https://example.com
Enter comma separated list of API endpoints for consensus nodes: https://example.com
Enter the network name: goerli
Found 24 validators, recovering...
Generating keystores [####################################] 100%
Keystores for vault {vault} successfully recovered to {keystores_dir}
To mitigate excessive gas costs, operators can pass the --max-fee-per-gas-wei
flag when starting Operator Service (or
configure this variable via Environment Variables) to set the maximum base fee they are happy to pay for both validator
registrations and Vault harvests (if Operator is started using the --harvest-vault
flag).
--pool-size
can be passed as a flag with both start and create-keys commands. This flag defines the number of CPU
cores that are used to both load keystores and create keystores. By default, Operator Service will use 100% of the CPU
cores.
Setting --pool-size
to (number of CPU cores) / 2 is a safe way to ensure that Operator Service does not take up too
much CPU load and impact node performance during the creation and loading of keystores.
This command allows you to self-report your validator keys to the Rated Network, ensuring that your validator set is tracked and updated on the Rated Explorer.
To use the rated-self-report
command, you will need to provide the following parameters:
--data-dir
: Path where the vault data will be placed. Default is ~/.stakewise.--vault
: The vault address.--network
: The network of your vault (e.g., mainnet, holesky).--pool-tag
: The pool name listed on the Explorer (optional).--token
: OAuth token for authorization.
Here's an example of how to use the command:
python src/main.py rated-self-report --vault <your-vault-address> --network <network-name> --pool-tag <pool-tag> --token <your-oauth-token> --data-dir <path-to-data-dir>
- Dmitri Tsumak - [email protected]
- Alexander Sysoev - [email protected]
- Evgeny Gusarov - [email protected]