ERC20 Votes
Se asume el conocimiento de ERC20 Snapshot, por favor consulte nuestro artículo sobre ERC20 Snapshot para una introducción al tema.
ERC20 Votes no se encarga realmente de llevar a cabo la votación, sigue siendo un token ERC20 regular con capacidades de snapshot y votación delegada. La votación es manejada usualmente por contratos de gobernanza.
La delegación significa que una dirección puede prestar su poder de voto a otra dirección sin transferirle sus tokens.
A diferencia de ERC20 Snapshot, no mantiene snapshots de los balances de los tokens, sino que mantiene snapshots del poder de voto de las direcciones.
Hay un par de motivaciones para esto:
- Esto permite a los accionistas pasivos participar en la gobernanza delegando su poder de voto
- Las cuentas con saldos pequeños pueden votar sin gastar gas, porque el delegado está votando en su nombre. Esto ahorra gas a nivel del ecosistema. Si todos los participantes han delegado en 5 delegados, entonces solo se realizan 5 votos para un elemento a votar, en lugar de posiblemente miles.
- Y por supuesto, hacer snapshots (checkpoints) es necesario para prevenir el doble voto, al igual que lo hace ERC20 Snapshot.
ERC20 Votes hereda de ERC20, ERC6372 y ERC5805. Esto significa que tiene toda la funcionalidad de un token ERC20 con atributos adicionales descritos a continuación.
Funcionalidad de ERC5805
getVotes(address delegate)
Esta función toma la dirección de una cuenta y devuelve el poder de voto total que tiene. Esto puede ser mayor que balanceOf(delegate) si otras direcciones le han delegado su poder de voto.
delegate(address delegatee)
Esta función permite a msg.sender delegar su poder de voto al delegatee y el delegatee votará en nombre de msg.sender. Tenga en cuenta que los tokens no se transfieren al delegatee, solo el poder de voto. La delegación puede ser modificada o revocada en cualquier momento llamando a delegate nuevamente con un delegatee diferente o con address(0).
La delegación es todo o nada. No hay opción de delegar una fracción del poder de voto.
Es importante tener en cuenta que una dirección debe delegar en sí misma antes de que se cuenten sus votos. Esta peculiaridad se introduce por razones de eficiencia de gas.
delegates(address account)
Esta función devuelve la cuenta a la que la account pasada en el argumento ha delegado su poder de voto.
delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)
La función delegateBySig permite a un usuario delegar su poder de voto a través de una transacción sin gas y hacer que otra cuenta pague la tarifa de gas y ejecute la transacción.
La expiración (expiry) establece el tiempo durante el cual la delegación es válida, y v, r y s son los componentes de la Firma Digital de Curva Elíptica (Elliptic Curve Digital Signature).
Se espera que esta firma esté en el formato EIP 712. Internamente, el contrato incrementa el nonce por dirección, lo cual se describe a continuación.
nonces(address account)
Las firmas requieren un nonce para prevenir ataques de repetición (replay attacks), por lo que el rastreador interno del nonce se expone a través de esta función. Esto permite al firmante saber qué valor deben firmar a continuación.
getPastVotes(account, timepoint)
Como se discutió en nuestro artículo sobre ERC20 Snapshot, a menos que se hagan snapshots de los balances de las cuentas, puede ocurrir un ataque de doble voto. Aquí es donde un contrato de votación (ballot contract) buscaría un snapshot pasado.
A diferencia de ERC20 Snapshot, un snapshot no es activado por una dirección llamando a la función snapshot. Un snapshot se activa por cuenta cuando ocurre uno de estos eventos:
- minteo
- quema
- transferencia
- alguien delega sus votos
Cada vez que ocurre uno de estos eventos, un struct que contiene el poder de voto y el timestamp se añade a un array que almacena el historial de poder de voto de ese usuario.
Al igual que ERC20 Snapshot, ERC20 Votes hará una búsqueda binaria sobre los timestamps para encontrar el primer checkpoint después del timepoint. Se devuelve el poder de voto en ese timepoint.
Esto significa que, a diferencia de ERC20 Snapshot, no hay un id de snapshot “global”. Si desea consultar un punto en el pasado, selecciona un timestamp o número de bloque y lo proporciona como el “timepoint” a la función.
Eventos
ERC5805 tiene dos eventos que significan lo que su nombre indica: DelegateChange y DelegateVotesChanged.
ERC5805 es una interfaz, no un token
En este artículo, estamos explicando ERC20 Votes, pero eso no significa que ERC5805 tenga que ser un token fungible. Podría ser un NFT, o incluso una contabilidad de votos gestionada de otra manera, como una entidad centralizada asignando votos a direcciones, pero queriendo mantener un historial inmutable de cómo se distribuyó el poder de voto.
ERC6372
Supusimos en cierta medida que el contrato estaba usando block.timestamp para la contabilidad de cómo registrar el checkpoint. Sin embargo, algunos contratos podrían usar el block.number o alguna función monótonamente creciente de estas variables globales.
ERC6372 es un estándar para permitir a los contratos consultar qué tipo de “reloj” está usando el contrato. Tiene dos funciones:
clock()
Esto devuelve un uint48 que podría ser el número de bloque o el timestamp del bloque o una función de estos. uint48 fue elegido porque tiene suficientes bits para representar todas las representaciones sensatas del tiempo y el número de bloque más hacia el futuro de lo que la humanidad ha registrado en su historia.
CLOCK_MODE()
Sí, una función en snake-case completamente en mayúsculas es muy inusual en Solidity, pero eso es lo que especifica el EIP. Esto devuelve un string que le dice al lector qué unidad usa el reloj.
- Si es un timestamp, será
“mode=timestamp”. - Si es un número de bloque será
mode=blocknumber&from=default.
Esto significa que simplemente está usando la variable block.number. Si estuviera comenzando desde otro bloque, debe especificar el chain ID y el número de bloque en el que está comenzando. Por ejemplo, el chain ID de Avalanche es 43114, por lo que la respuesta de CLOCK_MODE() sería mode=blocknumber&from=43114:100 si estuviera comenzando desde el bloque 100.
EIP 6372 no tiene eventos.
Para más detalles, consulte el EIP, que en realidad es bastante legible. Tenga en cuenta que este EIP no está finalizado.
Resumen de diferencias con ERC20 Snapshot
Noción del tiempo
- ERC20 Votes tiene una noción explícita del tiempo
- ERC20 Snapshot usa ids incrementales que aumentan con el tiempo como un subproducto de ser un contador
Qué se registra
- ERC20 Votes hace snapshots del poder de voto
- ERC20 Snapshot hace un seguimiento de los balances
Cuándo se actualizan los checkpoints
- ERC20 Votes se actualiza cada vez que ocurre una delegación o transferencia
- ERC20 Snapshot necesita una llamada explícita a “_snapshot()”
Si usar ERC20 Snapshot o Votes
La decisión de usar ERC20 Snapshot o Voting depende principalmente de si existe la necesidad de delegar votos, o más abstractamente, algún derecho que confiere el token ERC20.
Aprenda más
Consulte nuestro bootcamp de programación en solidity avanzado y nuestras otras ofertas de bootcamp de blockchain.
Publicado originalmente el 23 de febrero de 2023