Tiempo estimado: 4 minutos de lectura
¿Qué es una lista blanca en contrato de NFT?
Una lista blanca en contrato de NFT es un conjunto de datos que permite comprobar en la blockchain si una transacción está autorizada para para acuñar un nuevo NFT del smart contract.
Una solución típica consite en añadir al contrato la lista de direcciones de los wallets de los usuarios autorizados. Es una opción muy sencilla con dos problemas principales:
- Requiere almacenar mucha información en el contrato inteligente si la lista de autorizados es grande. Esto repercute en un aumento de los costes de gas.
- Es preciso conocer a priori la lista de direcciones autorizadas o en su defecto, actualizarla sobre la marcha (transaccionando sobre la blockchain) con el consiguiente gasto en gas.
Como solución alternativa se presenta en este artículo la utilización de un árbol de Merkle para crear una lista de códigos preautorizados para acuñar un nuevo NFT en el contrato.
¿Qué es un árbol de Merkle?
Un árbol de Merkle es una estructura de datos en árbol binario que relaciona cada nodo del árbol con los hashes de los nodos hijo. El hash de los datos iniciales se representa en los nodos hijo, las hojas del árbol. A partir de ahí la estructura se desarrolla en nodos padre, las ramas del árbol. Al árbol concluye en el hash del nodo raíz, el llamado raíz de Merkle.
El esquema, adaptado de la Wikipedia, sería el siguiente:
Entre las utilidades de un árbol de Merkle se puede destacar la de verificar si un dato pertenece a alguna de las hojas a partir del hash del nodo raíz y una lista de hashes del árbol llamada prueba de Merkle.
Las verificaciones son procesos computacionalmente eficientes, por tanto adecuadas para ejecutar en la blockchain.
Los árboles de Merkle se usan intensivamente en muchas redes blockchain: cada bloque contiene un árbol de las transacciones validadas. Para verificar una transacción tan sólo hace falta el raíz de Merkle y la prueba.
¿Cómo crear una lista blanca en contrato de NFT mediante un árbol de Merkle?
La idea es sencilla: la lista blanca se compone de N códigos aleatorios alfanuméricos, por ejemplo en formato UUID.
Se crea un árbol de Merkle tomando como datos iniciales los códigos de la lista blanca. El árbol se compondrá de las hojas (hash de los datos iniciales), las ramas, el raíz de Merkle y las pruebas de Merkle.
A cada usuario autorizado para acuñar un NFT se le suministra un código válido y su correspondiente prueba de Merkle.
Desde la DApp que interactúa con el contrato de NFT se comprobará en la cadena (on-chain) si el código suministrado pertenece al árbol usando la correspondiente prueba y el hash raíz (almacenado en el smart contract). Si la verificación es correcta, se permitirá acuñar un nuevo NFT.
Para llevar a cabo este esquema se puede usar la librería Merkle-Tree en JavaScript de OpenZeppelin.
import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
import crypto from 'crypto';
// Creates the whitelisted codes
export const whitelistCodes = Array.from({ length: 300 }, () => [crypto.randomUUID()]);
// Creates Merkle tree from the whitelisted codes
const tree = StandardMerkleTree.of(whitelistCodes, ["string"]);
// Merkle root should be stored in the smart contract
const merkleRoot = tree.root;
// Codes and proofs should be delivered to the authorized users
for (const [i, v] of tree.entries()) {
let proof = tree.getProof(i);
console.log('Code:', v);
console.log('Proof:', proof);
}
La verificación on-chain del código y la prueba se puede efectúar en Solidity mediante el contrato de utilidad MerkleProof de OpenZeppelin:
function mint(string calldata code, bytes32[] memory proof, address to) external {
if (!MerkleProof.verify(proof, _merkleRoot,
keccak256(bytes.concat(keccak256(abi.encode(code))))))
revert NonexistentCode();
_safeMint(to, uint256(keccak256(bytes.concat(keccak256(abi.encodePacked(code))))));
}
Conclusión: creando listas blancas escalables
En el artículo se ha explorado una forma sencilla de crear una lista blanca para autorizar a los usuarios de una DApp de NTFs a acuñar un nuevo token.
Ante esquemas a priori más sencillos como almacenar directamente en el smart contract la lista de direcciones permitidas, se presenta la posibilidad de usar un árbol de Merkle.
Frente a una mayor complejidad se logra una solución escalable, solo requiere almacenar en el contrato el hash raíz del árbol, y anónima, ya que no es preciso conocer de antemano las direcciones de los usuarios.
¿Has necesitado alguna vez autorizar una lista de usuarios para acceder a un token? ¿Qué tipo de listas blancas has implementado?
Si el uso de un árbol de Merkle te ha parecido una solución interesante, puedo ayudarte a desarrollarla más a fondo para tu caso particular: contáctame y hablemos. ¡Muchas gracias!