Leyendo tablas del contract SimpleAssets (CryptoLions) desde JavaScript
Tal vez nuestros intereses sean los de comprar y/o vender objetos digitales coleccionables o consumibles (tokens fungibles o no fungibles) o tal vez nuestro objetivo sea desarrollar el juego que se lleve el próximo premio de “Game of the Year” pero, en cualquier caso, consultar la blockchain de WAX para conocer el contenido de un wallet siempre será algo necesario. Una de las principales ventajas de una blockchain, como ya sabemos, es su transparencia e inmutabilidad. Todo lo que ocurre queda registrado en una transacción y esta, a su vez, en un bloque de la cadena. Cada vez que se crea una carta coleccionable (NFT) para un juego se guarda un registro en la cadena. Cuando esa carta, ese token, es transferido o vendido, se escribe otro registro en la cadena, y así sucesivamente. Si tenemos en cuenta la cantidad de tokens y de transacciones que ocurren en cada momento sobre la cadena, tratar de localizar un token o todo el listado de tokens de un usuario sería una labor titánica.
Por fortuna, CryptoLions ha pensado en ese detalle y nos facilita el trabajo gracias a las tablas de datos que incluye su contract.
SimpleAssets contract: Tabla “sassets”
El contract SimpleAssets almacena en la tabla sassets toda la información que necesitamos acerca de los tokens NFT que se han creado con el mismo contract. Podemos consultar esa tabla para conocer el ID de un token, su creador, su propietario, los datos que contiene, etc. Pero, además, podemos aplicar filtros sobre esa tabla para obtener búsquedas más precisas.
En el anterior artículo, “SimpleAssets: Análisis del Contract y Creación de NFTs desde el Explorador de Bloques de WAX”, vimos cómo podíamos acceder a las tablas y a las acciones que contiene el contract desde el explorador https://wax.bloks.io/
En esta ocasión vamos a centrarnos en la tabla “sassets”.
Una vez seleccionada la tabla, podremos acceder a los parámetros bajo la sección “Enter Parameters”. En el campo “scope” escribimos el nombre de la cuenta de usuario que queremos analizar y pulsamos sobre el botón verde “Refresh”
Como vemos, el listado nos muestra todos los tokens de tipo NFT que están en posesión de este usuario.
Podemos centrar un poco más la búsqueda si en los campos Lower Bound y Upper Bound especificamos una cuenta de autor veremos solo los NFT que han sido creado por el autor especificado y que estén en posesión del usuario.
Accediendo al contract desde JavaScript
El objetivo final de estos artículos es introducir al lector en cómo gestionar el contract “simpleassets” desde JavaScript y ya es hora de ponernos manos a la obra. En primer lugar, vamos a crear una carpeta para el proyecto y nos aseguraremos de que tenemos un entorno de desarrollo para JavaScript adecuado. Para estos artículos voy a utilizar Node.js
Para más información es recomendable consultar la documentación oficial de CryptoLions acerca del contract SimpleAssets: https://github.com/CryptoLions/SimpleAssets
Una vez tenemos la carpeta abierta con nuestro editor de código favorito (para estos ejercicios voy a utilizar Visual Studio Code) crearemos el archivo package.json. Puedes crearlo de forma manual o utilizar el asistente “npm init”.
Una vez creado el archivo package.json instalamos los siguientes módulos necesarios:
npm install eosjs node-fetch
Con lo que el archivo tendrá este aspecto:
{
"name": "simpleassetstest",
"version": "1.0.0",
"description": "Testeando el contract SimpleAssets",
"main": "index.js",
"scripts": {
"dev": "index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "MarcosDK",
"license": "ISC",
"dependencies": {
"eosjs": "^21.0.2",
"node-fetch": "^2.6.0"
}
}
Creamos el archivo index.js que utilizaremos nada más para llamar a las funciones de ejemplo que vamos a utilizar y que definiremos en un archivo aparte llamado simpleassets.js y que también crearemos.
Podríamos hacerlo todo en un solo archivo pero, por motivos de limpieza de código, vamos a separar la definición de las funciones del resto del código.
Nuestro primer objetivo es leer los tokens NFT de la cuenta de un usuario concreto. Teniendo en cuenta que JavaScript es un lenguaje asíncrono y que el acceso a la blockchain, al igual que a otra base de datos, puede sufrir demoras, nos aseguraremos de esperar por los resultados utilizando promesas. El aspecto de nuestro fichero index.js podría ser este:
const simpleassets = require('./simpleassets');simpleassets.leerNFT('kbjqu.wam')
.then(data => {
console.log(data);
});
});
Requerimos el archivo “simpleassest.js” que definiremos a continuación y que contiene las funciones de gestión del contract. A continuación, llamamos a nuestra función leerNFT pasando como parámetro el nombre de usuario que queremos investigar.
La función esperará los resultados para, finalmente, mostrarlos en consola con un log.
La llamada a la función leerNFT es muy intuitiva, vamos a ver ahora cómo la definimos.
Función leerNFT
Editamos nuestro archivo simpleassets.js y añadimos la información necesaria para que nuestro código pueda comunicarse con la blockchain.
En primer lugar, requerimos los módulos eosjs y node-fetch que instalamos nada más empezar.
const {JsonRpc} = require(‘eosjs’);
const fetch = require(‘node-fetch’);
A continuación, creamos un enlace RPC con la blockchain de WAX utilizando uno de los servidores RPC que los gild de WAX nos ofrecen. Para este ejemplo he utilizado https://api.waxsweden.org pero puede utilizarse cualquier otro nodo RPC.
const rpc = new JsonRpc(‘https://api.waxsweden.org', {fetch});
A estas alturas del artículo es posible que más de uno se esté preguntando por qué si vamos a acceder a la blockchain de WAX estoy utilizando un módulo de JavaScript que se diseñó para acceder a la blockchain de EOS. Muy observador.
WAX es una blockchain que deriva directamente de EOS hasta tal punto que adaptar a WAX los programas y contracts creados para EOS es sumamente sencillo. Para muchas situaciones lo único que tenemos que cambiar es el nodo RPC al que accedemos. Hasta el momento de escritura de este artículo no existe ninguna librería JavaScript específica para WAX, al menos que este humilde servidor conozca por lo que no nos queda otra que utilizar el módulo eosjs. Sin embargo, como veremos a lo largo de esta serie, esto no supone ningún problema en absoluto.
Para más información acerca del módulo eosjs recomiendo visitar su documentación oficial: https://developers.eos.io/manuals/eosjs/latest/index
La librería de funciones que nos ofrece el módulo eosjs contiene la función rpc.get_table_rows que nos permite acceder a una tabla de datos de un contract específico y filtrar sus contenidos a través de los parámetros que le indiquemos. Si deseamos localizar todos los NFT que están en su propiedad, los parámetros serían:
json: true,
code: 'simpleassets', // contract a acceder
scope: usuario, // Usuario propietario del wallet
table: 'sassets', // tabla del contract
limit: 100, // Límite de registros a listar
Y este sería el aspecto final de nuestro archivo simpleassets.js:
const {JsonRpc} = require('eosjs');
const fetch = require('node-fetch');const rpc = new JsonRpc('https://api.waxsweden.org', {fetch});module.exports.leerNFT = function (usuario) {
return new Promise(resolve => {
rpc.get_table_rows({
json: true,
code: 'simpleassets', // contract a acceder
scope: usuario, // Usuario propietario del wallet
table: 'sassets', // tabla del contract
limit: 100, // Límite de registros a listar
}).then(response => {
resolve(response);
}).catch(error => {
console.log(error);
});
});
}
Si ejecutamos nuestro código desde el terminal con la instrucción node index.js obtendremos un resultado similar a este:
Vamos a ser más específicos. Supongamos que queremos ver únicamente los NFT de un autor determinado. Ahora deberemos añadir los siguientes parámetros:
key_type: 'i64',
index_position: 2,
table_key: 'author', // Clave de búsqueda
lower_bound: '3dkrenderwax', // Nombre del autor de NFT a buscar
upper_bound: '3dkrenderwax',
y el código de nuestro archivo “simpleassets.js” mostrará este aspecto:
const {JsonRpc} = require('eosjs');
const fetch = require('node-fetch');const rpc = new JsonRpc('https://api.waxsweden.org', {fetch});module.exports.leerNFT = function (usuario) {
return new Promise(resolve => {
rpc.get_table_rows({
json: true,
code: 'simpleassets', // contract a acceder
scope: usuario, // Usuario propietario del wallet
table: 'sassets', // tabla del contract
key_type: 'i64',
index_position: 2,
table_key: 'author', // Clave de búsqueda
lower_bound: '3dkrenderwax', // Nombre del autor de NFT
upper_bound: '3dkrenderwax',
limit: 100, // Límite de registros a listar
}).then(response => {
resolve(response);
}).catch(error => {
console.log(error);
});
});
}
Para finalizar con nuestra función, si su ejecución tiene éxito, la promesa devolverá el listado de registros leído en formato JSON. En caso de error, catch atraparía el error y nos lo mostraría en la consola.
Ahora, desde nuestro programa principal “index.js”, podemos acceder a todo el listado de registros y a cada elemento que contiene. Hay que tener en cuenta que la función “get_table_rows” no sólo devuelve los registros; también añade información adicional, como un indicador lógico para saber si quedan más registros por leer más allá del límite indicado con el parámetro “limit”. Por ese motivo, debemos extraer el array de registros de entre toda la información devuelta. Los registros están contenidos en el elemento rows del objeto devuelto.
Veamos un ejemplo final: Mostraremos un listado con los números ID y la URL de las imágenes de todos los NFT creados por el autor “radaquesttcg” del usuario “kbjqu.wam”
En el archivo simpleassets.js solo es necesario modificar estas 2 líneas de los parámetros:
lower_bound: 'radaquesttcg',
upper_bound: 'radaquesttcg',
Y nuestro archivo index.js quedará de esta forma:
const simpleassets = require('./simpleassets');simpleassets.leerNFT('kbjqu.wam')
.then(data => {
let registros = data.rows;
registros.forEach(element => {
let mdata = JSON.parse(element.mdata);
console.log(element.id, mdata.img);
});
});
Resultado (en el momento de escribir el artículo):
¡Nos vemos en la próxima entrega!