Simple Lido keys and validators HTTP API. It will be possible to launch it on someone's machine and fetch actual Lido keys from all sources. API will also provide HTTP methods for Automating Validator Exits.
NodeOperatorRegistry
is a Lido contract that manages a сurated set of node operators, stores their signing keys;Module
is a contract in charge of different validators subsets;Curated
(modified version of NodeOperatorRegistry
), Community
, DVT
, Offchain
or L2
upgrade for Curated subset;StakingRouter
is a new contract that is responsible for modules management, reserve allocation and rewards distribution.Lido node operators keys and validators are used in a lot of services: Oracle, Council Daemon, MEV Monitoring, BalVal, Node Operators Widget. Also Node Operators need fetching keys for automating exits. Currently Lido supports only Curated
validators subset handled by NodeOperatorRegistry
contract. But in the future validators set can be expanded with DVT
and Community
validators. The StakingRouter
contract was proposed for implementing modular approach of managing different subsets of validators. It will support any number of Curated
, Community
and DVT
modules. These modules could store keys on-chain, off-chain, on L2 or in any other way. Services will have to support fetching keys from all these modules.
StakingRouter
will be implemented;StakingRouter
could support any number Curated
, Community
, DVT
, off-chain and L2 Curated
modules;L1
contract;L1
contract address will not be changed;keysOpIndex
or other value to understand that keys list was changed (will be renamed to nonce
);operator id
;Community
/DVT
modules will have some group id for keys to determine ownership of keys;blockHash
in metadata of each module should be equal);EL
state. It will NOT return any arbitrary state for arbitrary blockNumber
. Keys API is NOT an indexer.Keys API service will work with all StakingRouter
modules. We chose modular way of implementation. For each type of module we will have separate library. Modules data will be stored in separate tables too. For example, we will have CuratedKey
and CommunityKey
tables. Every library will contain its own {ModuleName}Meta
table with EL data. Meta will include keyOpIndex
(nonce
) value. API will run cron job to update keys in db for all modules to latest EL block
. At the moment API supports only NodeOperatorRegistry
keys.
API will have endpoint for Automating Validator Exits. Information about validators state will be fetched from beacon node and stored in database. We will implement this algorithm as ValidatorState
library.
In the next sections we will describe technical details of each part.
In this section we will describe general interface of libraries for StakingRouter
modules. Each library will contain methods for fetching keys and other data from modules storages, methods for writing and reading data to the database.
As was mentioned in requirements section Keys API service should keep modules data in storage in consistent state. To fulfill this condition we will fetch data from modules storages for the same blockHash
and write it in database in transaction.
As described earlier, at the moment Lido stores keys on-chain in NodeOperatorRegistry
contract. We have already implemented Registry
library for fetching keys and operators from this contract, store in database and update database state to latest EL block
.
Registry
library contains RegistryKey
, RegistryOperator
, RegistryMeta
tables.
Updating keys in Registry
library is based on comparing meta information in contract and database. We read blockHash
,blockNumber
values of latest
block from EL
and fetch keyOpIndex
from NodeOperatorRegistry
by blockHash
. If current blockNumber
is less than previous or keyOpIndex
wasn't changed, keys in database will not be updated. Otherwise, keys and operators will be updated in library's database.
The same algorithm we consider to have in other modules libraries.
Keys API will also provide endpoints for working with validators. This library will fetch keys from beacon node, store data in database and support it in actual state.
Library will contain Validator
, Meta
tables.
Algorithm of fetching validators, update and store in database:
Fetch CL
finalized block by request to Beacon node to get root
and slot
of last finalized block
Compare slot
from Meta
table and received slot
on 1 step. If Meta
is empty or slot number in database less than received slot
on 1 step, go on 3 step. Otherwise stop algorithm execution.
Fetch EL block information by request to Beacon node by slot root parameter. This information is needed to check modules' keys relevance compare to validators in API's database:
Based on 10 assumption we need RegistryMeta.block_number
be newer than or equal to ValidatorMeta.block_number
.
Fetch all validators for slot_root
received on 1 step by request.
Write Meta
and Validators
in transaction in database.
Cron job with this algorithm will be run every 10 seconds.
GET /v1/keys
Endpoint returns list of keys for all modules.
Query:
used
- filter for used/unused keys. Possible values: true/false;operatorIndex
- filter for keys of operator with index operatorIndex
;Example:
Response of this endpoint could be very large but we can’t have a pagination here since data could be updated in the process.
If API returns 425 code, it means database is not ready for work
GET /v1/keys/{pubkey}
Return key by public key with basic fields. pubkey
should be in lowercase.
Example:
POST /v1/keys/find
Returns all keys found in db.
Request body:
Response:
Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules
Endpoint returns list of staking router modules.
Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules/{module_id}
module_id
- staking router module contact address or id;
Endpoint return information about staking router module;
Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules/keys/
Return keys for all modules grouped by staking router module.
Query:
used
- filter for used/unused keys. Possible values: true/false;operatorIndex
- filter for keys of operator with index operatorIndex
;Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules/{module_id}/keys
module_id
- staking router module contact address or id;
Endpoint returns list of keys for module.
Query:
used
- filter for used/unused keys. Possible values: true/false;operatorIndex
- filter for keys of operator with index operatorIndex
;Response:
Response depends on module type
Example:
If API returns 425 code, it means database is not ready for work
POST /v1/modules/{module_id}/keys/find
module_id
- staking router module contact address or id;
Returns all keys found in db.
Request body:
Response:
Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules/{module_id}/validators/validator-exits-to-prepare/{operator_id}
module_id
- staking router module contact address or id;
This endpoint will return N of oldest lido validators for earliest epoch when voluntary exit can be processed for specific node operator and specific StakingRouter
module. Node operator will use this validators list for preparing pre-sign exit messages. API will find used
keys of node operator and find for these public keys N oldest validators in Validator
table. We consider active validators (active_ongoing
status) or validators in pending_initialized
, pending_queued
statuses. Module tables state fetched from EL
should be newer than Validator
table state fetched from CL
. Otherwise API will return error on request.
Query:
Only one filter is available. If both parameters are provided, percent
has a high priority.
percent
- Percent of validators to exit. Default value is 10.max_amount
- Number of validators to exit. If validators number less than amount, return all validators.Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules/{module_id}/validators/generate-unsigned-exit-messages/{operator_id}
module_id
- staking router module contact address or id;
Return unsigned exit messages for N oldest validators for earliest epoch when voluntary exit can be processed.
Query:
Only one filter is available. If both parameters are provided, percent
has a high priority.
percent
- Percent of validators to exit. Default value is 10.max_amount
- Number of validators to exit. If validators number less than amount, return all validators.Example:
If API returns 425 code, it means database is not ready for work
Approximate algorithm:
GET /v1/operators
List of operators grouped by staking router module
Query
Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules/{module_id}/operators/
module_id
- staking router module contact address or id;
List of SR module operators
Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules/{module_id}/operators/{operator_id}
module_id
- staking router module contact address or id;
operator_id
- operator index;
List of SR module operators
Example:
If API returns 425 code, it means database is not ready for work
GET /v1/modules/{module_id}/operators/keys
module_id
- staking router module contact address or id;
Query:
used
- filter for used/unused keys. Possible values: true/false;operatorIndex
- filter for keys of operator with index operatorIndex
;Example:
If API returns 425 code, it means database is not ready for work
GET /v1/status