Utilizando eosio singleton tables (en WAX Blockchain)

Categories Blog, Programación, WAXPosted on

Utilizamos las tablas dentro de un smart contract para almacenar la información como si de una base de datos se tratara. Gracias a los índices podemos acceder rápidamente a los registros que necesitamos y así ahorrarnos valiosos microsegundos de ejecución del código. Pero, en ocasiones, necesitamos almacenar datos simples que reflejen el estado actual de algo que estamos vigilando, como la versión actual del programa o un contador de eventos.

Este tipo de tablas no requieren de un índice ya que solo tendrán un registro al que acceder. Son las singleton tables.

Para ilustrar un caso de uso voy a realizar un ejercicio que creo pueda ser de bastante utilidad. Muchas veces me he encontrado en mi wallet de WAX con algunos NFTs totalmente inútiles o con valor residual. NFTs promocionales o de colecciones que esperábamos que pudieran monetizar, pero se han quedado en nada. Al final, la única solución para librarnos de la basura es quemándola. El problema es que quemar varios NFTs desde el interface de Atomic Market, si estamos en ese entorno, es un poco tedioso ya que hay que hacerlo de uno en uno.

Me propongo crear un smart contract que nos ayude a quemar los NFTs que le enviemos, sin importar el número, y que gracias a una tabla singleton lleve la cuenta de cuántos NFTs ha quemado.

Creamos la estructura de nuestro smart contract y seguiremos con la explicación. Puedes consultar el siguiente artículo para ver cómo preparar el entorno de programación y crear tu primer smart contract:


https://medium.com/eosbarcelona/c%C3%B3mo-preparar-el-entorno-de-desarrollo-para-crear-smart-contracts-en-la-blockchain-wax-desde-f9b8afc7a430

Declarando el objeto singleton


Lo primero que necesitamos es incluir la librería de eosio/singleton en nuestro archivo cabecera

#include <eosio/singleton.hpp>

Crearemos una tabla con los datos que deseamos almacenar. Para nuestro ejemplo solo vamos a utilizar un contador que irá incrementándose por cada NFT quemado.

TABLE burned
{
	uint64_t burned_items = 0;
} burned_reg;

Al mismo tiempo de crear la estructura de la tabla he aprovechado para inicializar el contador a 0 y también para declarar el objeto “burned_reg” como tipo ”burned”. Este objeto lo utilizaremos más adelante para acceder a la tabla.
A continuación, declaramos nuestro objeto singleton a partir de la tabla creada y le asignamos un nombre para que podamos acceder desde fuera del smart contract:



typedef singleton<"burned"_n, burned> t_burned;

Ahora ya podemos hacer uso de nuestra table singleton.

Recibiendo NFTs para borrar


Para que el smart contract borre (queme) todos los NFTs que reciba vamos a declarar una función pasiva que se quede a la escucha de eventos en la smart chain. Este tipo de funciones no requieren ser llamadas sino que se activan cuando ocurre el evento al que están asociadas; en nuestro caso, cuando recibimos un NFT.

Para transferir los NFTs del standard de AtomicAssets de una cuenta a otra se requiere hacer uso de la acción “transfer”, la cual recibe como parámetros la cuenta del emisor, la del destinatario, un array con los IDs de los NFTs transmitidos y un texto como mensaje (memo).

Desde nuestro smart contract podemos utilizar el atributo “on_notify” para capturar el evento de la transacción y actuar en consecuencia.

Declaramos una función con el atributo “eosio::on_notify” con los mismos parámetros que la función que queremos capturar, “atomicassets::transfer”

[[eosio::on_notify("atomicassets::transfer")]] void gettransfer(
	 name from,
	 name to,
	 vector<uint64_t> asset_ids,
	 string memo);

Ahora, cada vez que el smart contract reciba un NFT de AtomicAssets esta función se ejecutará automáticamente con los mismos parámetros de la transacción capturada.

Borrar array de NFTs


Lo que la función “transfer” envía es un array con los NFTs que se transmiten. Aunque solo enviemos 1 NFT será también un array de 1 elemento.

Para borrar los NFTs llamaremos a la acción “burnasset” del smart contract de AtomicAssets pero esta acción solo puede recibir el ID de un NFT en cada llamada por lo que si queremos quemar varios seguidos tendremos que implementar un bucle que recorra todos los elementos del array “asset_ids” para enviarlos de uno en uno.


for (auto it = asset_ids.begin(); it != asset_ids.end(); it++)
{
	action(
		permission_level{get_self(), name("active")},
		name("atomicassets"),
		name("burnasset"),
		make_tuple(get_self(), *it))
		.send();
}

Actualizar tabla singleton


Una vez quemados todos los NFTs enviados podemos proceder a actualizar la tabla singleton sumando las unidades quemadas al valor previamente almacenado.

En primer lugar, declaramos el objeto burned con la estructura y contenido de la tabla antes creada. El método “get_or_create” servirá para obtener esa estructura o para inicializarla en caso de no existir aún (primer acceso). Si es el caso, se iniciará el contador con el valor 0 tal y como indicamos en la definición del objeto burned_reg.

auto burned = _burned.get_or_create(_self, burned_reg);

Realizamos una sencilla operación de acumulación sumando a “burned_items” el total de NFTs recibidos (número de elementos del array):



burned.burned_items += asset_ids.size();

Y, para finalizar, actualizamos el registro de nuestra tabla:



_burned.set(burned, _self);

Código completo


El código completo se puede obtener en Github:
https://github.com/3dkrender/totheburning

Deja una respuesta

Tu dirección de correo electrónico no será publicada.