Palancas del Protocolo
El protocolo proporciona una serie de ajustes controlables por la DAO. Modificar cada uno de ellos requiere que el llamante tenga un permiso específico. Después de implementar la DAO, todos los permisos pertenecen a las aplicaciones DAO Voting
o Agent
, las cuales también pueden gestionarlos. Esto significa que, inicialmente, las palancas solo pueden ser modificadas mediante votación de la DAO, y otras entidades solo pueden permitirse lo mismo como resultado de esa votación.
A continuación se enumeran todas las palancas existentes, agrupadas por contrato.
Nota sobre la capacidad de actualización
Los siguientes contratos pueden ser actualizables mediante votación de la DAO:
LidoLocator
Lido
StakingRouter
NodeOperatorsRegistry
AccountingOracle
ValidatorsExitBusOracle
WithdrawalVault
WithdrawalQueueERC721
LegacyOracle
La capacidad de actualización está implementada ya sea mediante el kernel y los contratos base de Aragon o mediante instancias de OssifiableProxy.
Para actualizar una aplicación de Aragon, se necesita el permiso dao.APP_MANAGER_ROLE
proporcionado por Aragon.
Para actualizar una implementación de OssifiableProxy
, se necesita ser propietario del proxy.
Como se mencionó anteriormente, ambos pertenecen a las aplicaciones DAO Voting
o Agent
.
Todos los contratos actualizables utilizan el patrón de almacenamiento no estructurado para proporcionar una estructura de almacenamiento estable a través de las actualizaciones.
Algunos de los contratos todavía contienen datos de almacenamiento estructurado, por lo que el orden de herencia siempre es importante.
Lido
Quema de tokens stETH
Existe un contrato dedicado responsable de la quema de tokens stETH
.
La quema en sí misma es parte de los procedimientos centrales del protocolo:
- deducir la solicitud de retiro finalizada subyacente de
stETH
, verLido.handleOracleReport
- penalizar a los operadores de nodos morosos reduciendo a la mitad sus recompensas, ver Salidas y penalizaciones de los validadores
Estas responsabilidades están controladas por el rol REQUEST_BURN_SHARES_ROLE
, que se asigna tanto a los contratos Lido
como NodeOperatorsRegistry
.
Este rol nunca debe asignarse permanentemente a otras entidades.
Además de esto, la quema de tokens stETH
puede aplicarse para compensar penalizaciones/pérdidas por slashing según la decisión de la DAO.
Es posible a través de un rol más restrictivo REQUEST_BURN_MY_STETH_ROLE
, que actualmente no está asignado.
La diferencia clave es que ambos roles dependen de la asignación de stETH
proporcionada al contrato Burner
,
este último permite la quema de tokens solo desde el saldo del originador de la solicitud.
Pausa
- Mutador:
stop()
- Permiso requerido:
PAUSE_ROLE
- Permiso requerido:
- Mutador:
resume()
- Permiso requerido:
RESUME_ROLE
- Permiso requerido:
- Accesorio:
isStopped() returns (bool)
Cuando está pausado, Lido
no acepta envíos de usuarios, ni permite retiros de usuarios ni envíos de informes de oráculo. No se permiten acciones con tokens (quema, transferencia, aprobación de transferencias y cambio de asignaciones). Las siguientes transacciones revierten:
- transferencias de ether simples a
Lido
; - llamadas a
submit(address)
; - llamadas a
deposit(uint256, uint256, bytes)
; - llamadas a
handleOracleReport(...)
; - llamadas a
transfer(address, uint256)
; - llamadas a
transferFrom(address, address, uint256)
; - llamadas a
transferShares(address, uint256)
; - llamadas a
transferSharesFrom(address, uint256)
; - llamadas a
approve(address, uint256)
; - llamadas a
increaseAllowance(address, uint256)
; - llamadas a
decreaseAllowance(address, uint256)
.
Como consecuencia de la lista anterior:
- llamadas a
WithdrawalQueueERC721.requestWithdrawals(uint256[] calldata, address)
, y sus variantes; - llamadas a
wstETH.wrap(uint256)
ywstETH.unwrap(uint256)
; - llamadas a
Burner.requestBurnShares
,Burner.requestBurnMyStETH
, y sus variantes;
Las integraciones externas de stETH/wstETH en DeFi también se ven directamente afectadas.
Anular el contador de validadores depositados
- Mutador:
unsafeChangeDepositedValidators(uint256)
- Permiso requerido:
UNSAFE_CHANGE_DEPOSITED_VALIDATORS_ROLE
- Permiso requerido:
El método cambia de forma insegura el contador de validadores depositados. Puede ser necesario al integrar validadores externos a Lido (es decir, que hayan depositado antes y rotado sus credenciales de retiro tipo-0x00 a Lido).
Valores incorrectos pueden afectar la operación del protocolo.
Informe del oráculo
TODO: los informes del oráculo son impulsados por el comité
Control de acceso al depósito
El método Lido.deposit
realiza un depósito real (stake) de ether almacenado en el Consensus Layer,
pasando por StakingRouter
, su módulo seleccionado y finalmente el contrato oficial de depósito de Ethereum.
El método solo puede ser llamado por DepositSecurityModule
ya que el control de acceso es parte de la mitigación de vulnerabilidades de frontrunning en los depósitos.
Por favor, consulta LIP-5 para más detalles.
Límite de iteración del bucle de depósito
Controla cuántos depósitos de Ethereum pueden hacerse en una sola transacción.
- El parámetro
_maxDepositsCount
de la funcióndeposit(uint256 _maxDepositsCount, uint256 _stakingModuleId, bytes _depositCalldata)
- Valor predeterminado:
16
- Prueba de escenario
Cuando DSM llama a depositBufferedEther
, Lido
intenta registrar tantos validadores de Ethereum como sea posible dada la cantidad de ether almacenado en búfer. El límite se pasa como argumento a esta función y es necesario para evitar que la transacción falle debido al límite de gas del bloque, lo cual es posible si la cantidad de ether almacenado en búfer se vuelve suficientemente grande.
Recompensas de la capa de ejecución
Lido implementa un diseño arquitectónico propuesto en la Propuesta de Mejora de Lido #12 para recolectar las recompensas a nivel de ejecución (a partir del hardfork Merge) y distribuirlas como parte del informe del oráculo de Lido.
Estas recompensas de la capa de ejecución se acumulan inicialmente en el contrato dedicado LidoExecutionLayerRewardsVault
y consisten en tarifas de prioridad y MEV.
Existe un límite adicional para prevenir eventos drásticos de rebase de tokens.
Consulte el siguiente problema: #405
-
Modificador:
setELRewardsVault()
- Permiso requerido:
SET_EL_REWARDS_VAULT_ROLE
- Permiso requerido:
-
Modificador:
setELRewardsWithdrawalLimit()
- Permiso requerido:
SET_EL_REWARDS_WITHDRAWAL_LIMIT_ROLE
- Permiso requerido:
-
Accesores:
getELRewardsVault()
;getELRewardsWithdrawalLimit()
.
Limitación de la tasa de staking
Lido cuenta con un mecanismo de salvaguardia para prevenir pérdidas significativas en el APR frente a la demanda de la cola de entrada post-merge.
Las nuevas solicitudes de staking pueden estar limitadas con un límite móvil suave para la cantidad de staking por período deseado.
Esquema de explicación de límite:
* ▲ Límite de staking
* │..... ..... ........ ... .... ... Límite de staking = máximo
* │ . . . . . . . . .
* │ . . . . . . . . .
* │ . . . . .
* │──────────────────────────────────────────────────> Tiempo
* │ ^ ^ ^ ^^^ ^ ^ ^ ^^^ ^ Eventos de staking
-
Modificadores:
resumeStaking()
,setStakingLimit(uint256, uint256)
,removeStakingLimit()
- Permiso requerido:
STAKING_CONTROL_ROLE
- Permiso requerido:
-
Modificador:
pauseStaking()
- Permiso requerido:
STAKING_PAUSE_ROLE
- Permiso requerido:
-
Accesores:
isStakingPaused()
getCurrentStakeLimit()
getStakeLimitFullInfo()
Cuando el staking está pausado, Lido
no acepta envíos de usuarios. Las siguientes transacciones revierten:
- Transferencias simples de ether;
- llamadas a
submit(address)
.
Para más detalles, consulte la Propuesta de Mejora de Lido #14.
StakingRouter
Tarifa
La tarifa total, en puntos base (10000
correspondientes a 100%
).
- Modificador:
setFee(uint16)
- Permiso requerido:
MANAGE_FEE
- Permiso requerido:
- Accesor:
getFee() returns (uint16)
La tarifa se aplica a las recompensas de staking y se distribuye entre el tesoro, el fondo de seguro y los operadores de nodos.
Distribución de la tarifa
Controla cómo se distribuye la tarifa entre el tesoro, el fondo de seguro y los operadores de nodos.
Cada componente de la tarifa está en puntos base; la suma de todos los componentes debe sumar 1 (10000
puntos base).
- Modificador:
setFeeDistribution(uint16 treasury, uint16 insurance, uint16 operators)
- Permiso requerido:
MANAGE_FEE
- Permiso requerido:
- Accesor:
getFeeDistribution() returns (uint16 treasury, uint16 insurance, uint16 operators)
Credenciales de retiro de Ethereum
Credenciales para retirar ETH en el lado de la Capa de Ejecución
- Mutador:
setWithdrawalCredentials(bytes)
- Permiso requerido:
MANAGE_WITHDRAWAL_KEY
- Permiso requerido:
- Accesor:
getWithdrawalCredentials() returns (bytes)
El protocolo utiliza estas credenciales para registrar nuevos validadores de Ethereum.
NodeOperatorsRegistry
Lista de Operadores de Nodos
- Mutador:
addNodeOperator(string _name, address _rewardAddress, uint64 _stakingLimit)
- Permiso requerido:
ADD_NODE_OPERATOR_ROLE
- Permiso requerido:
- Mutador:
setNodeOperatorName(uint256 _id, string _name)
- Permiso requerido:
SET_NODE_OPERATOR_NAME_ROLE
- Permiso requerido:
- Mutador:
setNodeOperatorRewardAddress(uint256 _id, address _rewardAddress)
- Permiso requerido:
SET_NODE_OPERATOR_ADDRESS_ROLE
- Permiso requerido:
- Mutador:
setNodeOperatorStakingLimit(uint256 _id, uint64 _stakingLimit)
- Permiso requerido:
SET_NODE_OPERATOR_LIMIT_ROLE
- Permiso requerido:
Los Operadores de Nodos actúan como validadores en la cadena Beacon en beneficio del protocolo. Cada operador de nodo envía no más de _stakingLimit
claves de firma que serán utilizadas más tarde por el protocolo para registrar los validadores de Ethereum correspondientes. A medida que el comité oráculo reporta recompensas en el lado de Ethereum, se aplica una tarifa sobre estas recompensas, y parte de esa tarifa se envía a las direcciones de recompensa de los operadores de nodos (_rewardAddress
).
Desactivación de un operador de nodo
- Mutador:
setNodeOperatorActive(uint256 _id, bool _active)
- Permiso requerido:
SET_NODE_OPERATOR_ACTIVE_ROLE
- Permiso requerido:
Los operadores de nodo que se comporten mal pueden ser desactivados llamando a esta función. El protocolo omite los operadores desactivados durante el registro de validadores; además, los operadores desactivados no participan en la distribución de tarifas.
Gestión de las claves de firma del operador de nodo
- Mutador:
addSigningKeys(uint256 _operator_id, uint256 _quantity, bytes _pubkeys, bytes _signatures)
- Permiso requerido:
MANAGE_SIGNING_KEYS
- Permiso requerido:
- Mutador:
removeSigningKey(uint256 _operator_id, uint256 _index)
- Permiso requerido:
MANAGE_SIGNING_KEYS
- Permiso requerido:
Permite gestionar las claves de firma para el operador de nodo dado.
Las claves de firma también pueden ser gestionadas por la dirección de recompensa de un proveedor de firmas llamando a las funciones equivalentes con el sufijo
OperatorBH
:addSigningKeysOperatorBH
,removeSigningKeyOperatorBH
.
Reporte de nuevos validadores detenidos
- Mutador:
reportStoppedValidators(uint256 _id, uint64 _stoppedIncrement)
- Permiso requerido:
REPORT_STOPPED_VALIDATORS_ROLE
- Permiso requerido:
Permite informar que _stoppedIncrement
validadores adicionales de un operador de nodo se han detenido.
LegacyOracle
Lido
Dirección del contrato Lido.
- Accesor:
getLido() returns (address)
Lista de miembros
La lista de miembros del comité oráculo.
- Mutadores:
addOracleMember(address)
,removeOracleMember(address)
- Permiso requerido:
MANAGE_MEMBERS
- Permiso requerido:
- Accesor:
getOracleMembers() returns (address[])
El quórum
El número exacto de informes necesarios para finalizar el epoch.
- Mutador:
setQuorum(uint256)
- Permiso requerido:
MANAGE_QUORUM
- Permiso requerido:
- Accesor:
getQuorum() returns (uint256)
Cuando se recolecta el número quorum
de informes iguales para el epoch actual,
- el epoch se finaliza (no se aceptan más informes para él),
- el informe final se envía a Lido,
- se recopilan estadísticas y se evalúa la verificación de integridad.
Verificación de integridad
Para hacer que los oráculos sean menos peligrosos, podemos limitar el informe de recompensas por un aumento del 0.1% en el saldo y una disminución del 15% en el saldo, ambos valores configurables por el gobierno en caso de circunstancias extremadamente inusuales.
- Mutadores:
setAllowedBeaconBalanceAnnualRelativeIncrease(uint256)
ysetAllowedBeaconBalanceRelativeDecrease(uint256)
- Permiso requerido:
SET_REPORT_BOUNDARIES
- Permiso requerido:
- Accesores:
getAllowedBeaconBalanceAnnualRelativeIncrease() returns (uint256)
ygetAllowedBeaconBalanceRelativeDecrease() returns (uint256)
Estado actual de los informes
Para transparencia, proporcionamos accesos para devolver el estado de los informes de los demonios oráculo para el "epoch esperado" actual.
- Accesores:
getCurrentOraclesReportStatus() returns (uint256)
- devuelve el bitmap actual de informes, representando los oráculos que ya han enviado su versión del informe durante el epoch esperado, cada bit de oráculo corresponde al índice del oráculo en la lista actual de miembros,getCurrentReportVariantsSize() returns (uint256)
- devuelve el tamaño actual del array de variantes de informes,getCurrentReportVariant(uint256 _index) returns (uint64 beaconBalance, uint32 beaconValidators, uint16 count)
- devuelve el elemento actual del array de informes con el índice dado.
Epoch esperado
Los demonios oráculo pueden proporcionar sus informes solo para un epoch en cada marco: el primero. El siguiente accesor puede usarse para buscar el epoch actual que este contrato espera para los informes.
- Accesor:
getExpectedEpochId() returns (uint256)
.
Ten en cuenta que cualquier epoch posterior, que ya haya llegado y también sea el primer epoch de su marco, también es elegible para el informe. Si algún demonio oráculo lo informa, el contrato descarta cualquier resultado de este epoch y avanza al que acaba de ser informado.
Versión del contrato
Devuelve la versión inicializada de este contrato comenzando desde 0.
- Accesor:
getVersion() returns (uint256)
.
Especificación de Beacon
Establece y consulta la especificación configurable de la cadena Beacon.
- Mutador:
setBeaconSpec( uint64 _epochsPerFrame, uint64 _slotsPerEpoch, uint64 _secondsPerSlot, uint64 _genesisTime )
,- Permiso requerido:
SET_BEACON_SPEC
,
- Permiso requerido:
- Accesor:
getBeaconSpec() returns (uint64 epochsPerFrame, uint64 slotsPerEpoch, uint64 secondsPerSlot, uint64 genesisTime)
.
Epoch actual
Devuelve el epoch calculado a partir del timestamp actual.
- Accesor:
getCurrentEpochId() returns (uint256)
.
Información adicional del epoch
Devuelve el epoch actualmente reportable (el primer epoch del marco actual) así como su inicio y fin en segundos.
- Accesor:
getCurrentFrame() returns (uint256 frameEpochId, uint256 frameStartTime, uint256 frameEndTime)
.
Último epoch completado
Devuelve el último epoch que ha sido enviado a Lido.
- Accesor:
getLastCompletedEpochId() returns (uint256)
.
Información adicional de recompensas
Informa el saldo del beacon y su cambio durante el último frame.
- Accesor:
getLastCompletedReportDelta() returns (uint256 postTotalPooledEther, uint256 preTotalPooledEther, uint256 timeElapsed)
.