Implementación de contratos inteligentes en Solidity para NFTs
Resumen
¿Cómo implementar el sistema de ADN en un contrato inteligente?
En el emocionante mundo del desarrollo de contratos inteligentes, la implementación del sistema de ADN es una etapa crucial para el diseño de NFTs personalizados. Este proceso, que al principio puede parecer desalentador, se basa en algoritmos matemáticos y un método numérico para definir atributos únicos en los NFTs. Aquí veremos cómo llevar a cabo esta implementación utilizando Solidity.
¿Cómo crear un nuevo contrato inteligente para el ADN de los PlatziPunks?
Para mantener la cohesión del contrato, es vital separar la lógica del ADN en su propio contrato inteligente. Este enfoque respeta el principio de responsabilidad única, un pilar en el desarrollo de software.
// PlatziPunksDNA.sol// SPDX-License-Identifier: MITpragmasolidity^0.8.7;contractPlatziPunksDNA{// Implementa el sistema de ADN}
¿Cómo conectar el contrato ADN al contrato principal?
Una vez que creamos el contrato ADN, debemos integrarlo al contrato principal, en este caso, el contrato que maneja las funcionalidades del ERC721. Esto se hace mediante herencia: el contrato principal hereda las funciones del contrato ADN.
Los atributos, que definen la apariencia y características de cada NFT, deben establecerse en listas dentro del contrato ADN. Estas listas se basan en una preselección de atributos que pueden ser verificados o modificados usando recursos externos como getavatars.com.
// Parte de los atributos basestring[]private accessoriesType =["Gafas","Sombrero","Pendientes"];
¿Cómo implementar funciones para acceder a los atributos?
Dentro del contrato ADN, se deben definir funciones que calculen y devuelvan cada atributo basado en la estructura del ADN. Una función común a todos los atributos podría ser getDnaSection, que maneja el cálculo de secciones del ADN.
El ADN se segmenta en varias partes, cada una representando un atributo diferente. Utilizando operaciones de módulo, podemos seleccionar segmentos específicos del ADN para cada uno de estos atributos. Esta parte clave del proceso garantiza que el ADN se traduzca correctamente en un atributo visual.
Una vez configurado el sistema de ADN, el siguiente paso es calcular el ADN inicial para cada NFT. Este cálculo puede depender de variables aleatorias o IDs de tokens, añadiendo un elemento de aleatoriedad y exclusividad a cada NFT. Además, este ADN se debe convertir en URLs que puedan ser consumidas por APIs, enriqueciendo la metadata del JSON que define al NFT.
La importancia de la aleatoriedad en el ADN
La aleatoriedad en la generación del ADN es crucial para asegurar que los NFTs sean únicos e impredecibles. Esta característica no solo añade valor a cada NFT, sino que también mejora la experiencia del usuario, alentándolos a explorar las posibilidades creativas ilimitadas de sus NFTs personalizados.
Comienza ahora mismo a implementar tu propio sistema de ADN y observa cómo tus NFTs cobran vida de manera única y personalizada. Si ya has avanzado en esta tarea, no dudes en compartir tus logros y seguir contribuyendo a esta vibrante comunidad de desarrolladores. ¡El futuro del arte digital está en tus manos!
OJO: Las funciones de tipo Internal si se heredan en los contratos, si se requiere que la función no se herede a los otros contratos se debe especificar de tipo private
Muchas gracias por la especificación!
Si, esa función debió ser private, pero bueno. Como es pure tampoco creo que sea tan peligrosa que le haya dado permisos de más aunque siempre deberíamos dar el menor permiso posible.
Pense que se le aplicaba el modulo al capturar la propiedad, solo si la seccion del ADN tenia una valor mayor al array.
Válido, y el resultado es el mismo. Considero que es siempre mejor eliminar del código la mayor cantidad de condiciones posibles para que este sea mas limpio.
Valido, si es que quiere mantener la aleatoridad previamente obtenida.
Una pregunta de estilo... Cuál de las dos opciones es mejor para solidity? (explicito o no tan explicito?)
supuesto: f y g son funciones
opción 1:
a = f(g(x))
opción 2:
b = g(x)
a = f(b)
Quedo atento. saludos!
Como en cualquier lenguaje, ambas son correctas. Seguramente la opción 1 puede ser una pequeña optimización de gas (muy pequeña), ya que generan instrucciones distintas.
.
Sin entrar a tanto detalle, masomenos sería así:
.
Opción 1
Operacion
Explicación
g(x)
Hace una llamada, pasa x al contexto de g() y asigna el resultado en un temporal (tmp1)
f(g(x))
Utiliza el temporal resultante de g(x) y lo pasa por parámetro a f() copiándola en su contexto. El resultado lo guarda en otro temporal (tmp2)
a = f(g(x))
El temporal (tmp2) resultante lo guarda en una ubicación de memoria para a
.
Total de variables:
x en contexto de g()
tmp1
tmp1 en contexto de f()
tmp2
a
.
Opción 1
Operacion
Explicación
g(x)
Hace una llamada, pasa x al contexto de g() y asigna el resultado en un temporal (tmp1)
b = g(x)
El temporal (tmp1) resultante lo guarda en una ubicación de memoria para b
f(b)
Pasa b por parámetro al contexto de f() y el resultado lo asigna en un temporal (tmp2)
a = f(b)
El temporal (tmp2) resultante lo guarda en una ubicación de memoria para a
.
Total de variables:
x en contexto de g()
tmp1
b
b en contexto de f()
tmp2
a
La segunda opción genera más variables y ubica mayor cantidad de memoria volátil. Un analizador estático de Solidity como el que viene Remix te puede dar el detalle de los códigos de operación generados por la máquina virtual, y también un estimado de variación de gas. Seguramente serán alrededor de 10 unidades de gas haciendo una estimación burda.
Aún así, yo no sacrificaría legibilidad por optimizaciones de este tamaño. Es hasta más riesgoso en términos de seguridad, pero es tu decisión :)
Al guardar tanta informacion (todas las listas de atributos) en el contrato no estarias consumiendo muchos recursos y por lo tanto haciendo un contrato mas caro de ejecutar?
No entendí del todo el tema de la función aleatoria si es determinista o no… y por qué necesitaríamos ese servicio extra para usar en producción.
Alguien me podría orientar por favor?
Hola la verdad es que no entiendo porque hace 1*10 osea porque multiplica por 1, si todo numero multiplicado por 1 es el numero, no es media innecesario esa parte
Tengo una duda de esta función porque remix se queda pegado y no la ejecuta. Si bien el método push no funciona en en memoria, pero puedo asignar los valores manualmente. (importante mencionar que la hice publica para poder trabajar con ella)
La función la hice para ahorrarme ese montón de funciones que hizo el profe y pensé que si retorno un array con los datos es más sencillo.
function_getDNASection(uint _dna, uint8 _amountProperties)public pure returns(uint [] memory){ uint [] memory _dnaData =newuint[](_amountProperties);for(uint8 i =2; i <(_amountProperties *2); i +2){ uint _section = _dna %(1*10**(i)); uint y = i /2; _dnaData[y]= _section;}return _dnaData;}}