CURSO DE SOLIDITY
La importancia de la web3 y Solidity
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]/celo construyendo en Web3
[Link]
[Link]
[Link]
[Link]
[Link]
token/ERC20/[Link]
[Link]
token/ERC721/[Link]
[Link]
[Link]
sebastian
[Link]
[Link]
}
CURSO
[Link]
Más importante incluso que Solidity es la EVM (Ethereum Virtual Machine), por su
impacto cultural y tecnológico al implementarse en distintos blockchains.
Solidity es un lenguaje que compila hacia la EVM, por lo que es compatible con
redes como BSC, Polygon, RSK, TRON, etc.
// Version puede representar un rango. Ej >=0.7.0 <9.0.0
pragma solidity <version>;
// Declaración de un contrato, similar a una clase
contract <name> { // Name puede ser cualquier cosa
// Función de inicialización de un contrato
constructor() {
// Código de inicialización
}
}
Tipos de datos
int | uint <8-256>: Son números enteros, que pueden ser sin signo o con signo,
y que pueden tener una capacidad de 8 a 256 bits.
bool: Verdadero o flaso
address: Guarda direcciones de ETH de 160 bits (20 bytes), y puede tener
métodos extra como .transfer o .balance
string: Cadena de texto
bytes<8-256>: Cadena de bytes
Tipos de variables
Variables locales: Son aquellas que ocurren durante la ejecución. En la EVM es
la parte correspondiente a memoria volátil
Variables de estado: Son variables que se almacenan en la parte de la ROM de la
EVM. Es memoria persistente
Variables globales
msg: Toda transacción es un mensaje firmado. En este objeto vienen los datos de
dicho mensaje (sender, value, etc.)
tx: Represena la transacción, es distitna respecto a msg porque cosas como el
sender van variando conforme se concatenan llamadas entre contratos
block: Información respecto al bloque
Poner especial atención a la primer propiedad de block, ya que esa información irá
cambiando a lo largo del tiempo y no siempre seremos capaces de recuperarla (por lo
que no deberíamos depender de este dato en particular para alguna operación).
blockhash(uint blockNumber) returns (bytes32): hash of the given block when
blocknumber is one of the 256 most recent blocks; otherwise returns zero
[Link] (uint): current block’s base fee (EIP-3198 and EIP-1559)
[Link] (uint): current chain id
[Link] (address payable): current block miner’s address
[Link] (uint): current block difficulty
[Link] (uint): current block gaslimit
[Link] (uint): current block number
[Link] (uint): current block timestamp as seconds since unix epoch
gasleft() returns (uint256): remaining gas
[Link] (bytes calldata): complete calldata
[Link] (address): sender of the message (current call)
[Link] (bytes4): first four bytes of the calldata (i.e. function identifier)
[Link] (uint): number of wei sent with the message
[Link] (uint): gas price of the transaction
[Link] (address): sender of the transaction (full call chain)
//SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Estructura {
int cantidad;
uint cantidadSinSigno;
address direccion;
bool firmado;
constructor (bool estaFirmado) {
direccion = [Link];
firmado =estaFirmado;
}
Aqui la versión actualizada de la guia de estilos de solidity.
La recomiendo, asi se van familiarizando más con la terminología en inglés que
gobierna el mundo de la programación. Éxitos!!.
[Link]
Structs
Son estructuras de datos complejas, que agrupan una serie de datos.
struct <name> {
<type> <name>;
...
<type> <name>;
}
arreglos
override(Arreglos)
// Arreglos estáticos (n = cantidad de elementos)
<type>[n] <visibility> <name>;
// Arreglos dinámicos
<type>[] <visibility> <name>;
Funciones Array Dinámico
push: Se usa para adicionar elementos al final de un array
pop: Se usa para remover el último elemento de un array
uint[] data;
[Link](10);
[Link](20);
[Link](30);
// [10, 20, 30]
[Link]();
// [10, 20]
pragma solidity >=0.7.0 <0.9.0;
contract Clase {
struct Alumno {
string nombre;
uint documento;
}
Alumno [] public alumnos;
constructor() {
[Link](Alumno({ nombre: "Kinam", documento: 12345 }));
}
MAPPINGS Y ENUMS
Mapas
Los mapas son estructuras de datos de tipo llave-valor, que permiten apuntar un
tipo de dato a otro en forma de diccionario.
El tipo de la llave puede ser cualquier tipo de dato elemental, (por ejemplo,
uint), y el tipo de dato del valor puede ser cualquier dato elemental o complejo,
(se pueden inclusive hacer estructuras multidimensionales)
mapping(<key type> => <value type>) <visibility> <name>;
Enum
Representa una lista de valores posibles creados por el usuario, una variable del
tipo de enum declarado sólo puede tomar los valores enumerados.
enum { <value1>, ..., <valueN> }
mapping: Es un tipo especial de arreglo llamados arreglos asociativos.
enum: Coleccion ordenada de valores, el primer elemento corresponde con el elemento
0 (cero).
Enum types
Las enumeraciones son la forma de crear tipos de datos definidos por el usuario,
generalmente se usa para proporcionar nombres para constantes integrales, lo que
hace que el contrato sea mejor para el mantenimiento y la lectura. Las
enumeraciones restringen la variable con uno de los pocos valores predefinidos
enum <enumerator_name> {
element 1, elemenent 2,....,element n
}
pragma solidity >=0.7.0 <0.9.0;
contract Saldo {
mapping(address => uint) public balance;
enum Estado { Iniciado, Finalizado }
Estado public estadoDelContrato;
constructor() {
estadoDelContrato = [Link];
balance[[Link]] = 1000;
estadoDelContrato = [Link];
}
Estructuras de control
if/else: Estructura condicional. Ejecuta un bloque u otro dependiendo de una
evaluación booleana
for: Estructura cíclica que ejecuta un bloque de instrucciones un número
determinado de veces
while: Estructura cíclica que repite un bloque mientras se cumpla una condición
do while: Estructura cíclica que se asmilia al while, con la diferencia que
siempre se ejecuta almenos una vez
contract EstructuraDeControl {
uint[] public numeros;
string public resultado;
constructor(bool condicion) {
if (condicion) {
resultado = "Condicion True";
}
else {
resultado = "Condicion False";
}
for (uint iterador = 0; iterador < 10; iterador++) {
[Link](iterador);
}
}
EVENTOS
Los eventos son un tipo de dato que sirve para emitir avisos de que ocurrió alguna
acción en particular.
Puede ser utilizado por clientes para escuchar cambios importantes, y también
pueden utilizarse para indexar información.
Protocolos como TheGraph utilizan indexación de eventos para agregación de
información
contract Eventos {
uint[] public numeros;
string public resultado;
event NotificacionDeCondicion(bool condicion);
constructor(bool condicion) {
if (condicion) {
resultado = "Condicion True";
}
else {
resultado = "Condicion False";
}
emit NotificacionDeCondicion(condicion);
for (uint iterador = 0; iterador < 10; iterador++) {
[Link](iterador);
}
}
Permite conectar lo que pasa dentro de la Blockchain con el exterior porque a
tráves de un protocolo otras aplicaciones se pueden suscribir a ellos y escuchar
todo lo que está pasando en el Smart Contract.
Se usan para:
Registrar cambios que se hicieron
Feedback (Retroalimentación)
FUNCIONES
Funciones
Son piezas de código definidas por un nombre, parámetros y modificadores.
function <name>(<type> <parameter>..., [..., ]>)
<access modifiers>
<mutability modifiers>
<user defined modifiers>
<returns>(<type>) {
<content>
}
name: Nombre de la función
type: Tipo de dato
parameter: Nombre del parámetro
access modifier: public, private, internal, external
mutability modifier: view, pure. Ambas hacen que la función no cobre gas, y si
se omite, se asume que es una función que escribe en el storage de la EVM
user defined modifiers: Son modificadores definidos por el usuario, son
opcionales y se presentan en la siguiente clase
returns: Indica que la función retornará uno o más datos
Algunos puntos a pulir:
Las funciones pure. No leen ni modifican variables de estado y tampoco usan
ninguna variable global.
Existen funciones payable. Estas se usan cuando la función envía ether a alguna
dirección en la blockchain. Solo las funciones con tipo de retorno “payable” están
habilitadas para enviar ether.
Convenciones no obligatorias
En el desarrollo Solidity existe una convención no obligatoria y es que todos
los parámetros de una función empiecen con guión bajo.
function Suma( uint _numero1, uint _numero2 ) public pure returns (uint) {
return sumaInterna(_numero2, _numero2);
}
Tipos de función
public: son accesibles desde todo ámbito posible.
private: solo son accesibles desde el mismo contrato.
internal: solo son accesibles desde el mismo contrato y sus contratos
derivados.
external: solo accesibles desde fuera del contrato.
/ palabra clave o declaración - function
// nombre - Suma
// parámetros - ( uint numero1, uint numero2 )
// Modificador de acceso - public
// Tipo de función - pure
// Tipo de retorno - returns (uint)
function Suma( uint numero1, uint numero2 ) public pure returns (uint) {
return numero1 + numero2;
}
Un método no es lo mismo que un procedimiento…
Método es un término de la programación orientada a objetos, hace referencia a
una función que pertenece a una clase.
Una función devuelve un valor.
Un procedimiento ejecuta una serie de acciones (típicamente hace mutar las
variablesque definen el estado) y no devuelve nada.
¿Qué son las funciones en Solidity?
Las funciones son secciones de un programa que se encargar de ejecutar
instrucciones de forma independiente. Estas pueden recibir parametros para usarlos
dentro del código y pueden retornar una o más varibales. (Conocido como input y
output)
Tienen visibilidad al igual que las variables de estado, pueden ser.
Public: Totalmente accesible, sea cual sea el origen.
Private: Accesible únicamente a través de una función incluida en el mismo
contrato.
Internal: Accesible únicamente a través de otra función incluida en el mismo
contrato, o desde una función de un contrato que deriva del mismo. NO es accesible
desde un mensaje de un contrato externo o una transacción externa.
External: Accesible desde una cuenta de propiedad externa y a través de un
mensaje (llamada desde otro contrato). No es accesible desde una función del mismo
contrato o uno derivado del mismo.
MODIFICADORES
Los modificadores son funciones especiales por el usuario y que se añaden a otra
función para envolver su funcionamiento
modifier <name>(<type> <parameter>..., [,...]) {
<content>
}
La función revert() se utiliza para arrojar una excepción en nuestro smart contract
y revertir la función que la llama. Se puede agregar un mensaje como parámetro
describiendo el error.
modifier EsOwner() {
if ([Link] != owner) revert("Solo el dueño del contrato puede
modificarlo.");
_;
}
Dentro de un modificador de función se puede añadir toda la lógica que necesitemos,
no se limita a una sola validación, se pueden usar estructuras require dentro de
las mismas:
require( [Link] == owner, "Solo el propietario puede cambiar el nombre del
proyecto." );
EJEMPLO DE MODIFICADORES
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Modificadores {
//qureremos restrir que solo el que hizo el deploy del contrato
address private owner;
constructor() {
owner = [Link];
}
function Suma(uint numero1, uint numero2) public view EsOwner() returns(uint)
{
return numero1 + numero2;
}
modifier EsOwner() {
if ([Link]!= owner) revert();
_;
}
}
Manejo de errores
assert: Se utiliza para pruebas, compara dos valores
revert: Es un error que regresa todas las modificaciones de estado realizadas
durante la ejecución de la función. Recibe por parámetro un mensaje de error
require: Es una variación del revert que recibe por parámetro una expresión
booleana y revierte si esta expresión es falsa.
Cabe destacar que cualquier consumo de gas ejecutado hasta el momento de un revert
se debe pagar, porque el cómputo fué utilizado
En este blog explica con ejemplos y descripciones el uso para cada uno de estos
tipos de manejo de errores. Aqui una pequena parte traducida:
Utilice require ():
Validar las entradas del usuario, es decir. require (entrada <20);
Validar la respuesta de un contrato externo, es decir. require ([Link]
(cantidad));
Validar las condiciones estatales antes de la ejecución, es decir. require
([Link]> SOME_BLOCK_NUMBER) o require (balance [[Link]]> = amount)
Generalmente, debe usar require con mayor frecuencia
Generalmente, se utilizará hacia** el comienzo** de una función.
Utilice revert ()
Maneja el mismo tipo de situaciones que require (), pero con una lógica más
compleja.
Si tiene algún flujo lógico anidado complejo if / else, puede encontrar que
tiene sentido usar revert () en lugar de require ().
Utilice assert ()
Compruebe si hay desbordamiento / subdesbordamiento, es decir.c = a + b;
assert(c> b)
Compruebe invariantes, es decir. assert ([Link]> = totalSupply);
Validar el estado después de realizar cambios
Prevenir condiciones que nunca deberían ser posibles.
Por lo general, probablemente usaráassert con menos frecuencia.
Generalmente, se utilizará hacia el final de una función.
Tipos de almacenamiento
Storage: Memoria persistente. Es el más costoso. Similar a la memoria ROM
Memory: Variables temporales durante ejecución. Se asimila a la RAM
Calldata: Son constantes definidas en el entorno de ejecución de una variable.
No son modificables.
Memoria dinámica
La razón por la que un string necesita un sufijo que indique el uso de memoria, es
debido a que es memoria dinámica, por lo que calldata no puede alocar una cantidad
definida de memoria, por lo que tenemos que indicarle que esa variable la pase por
la memoria volátil (RAM/memory), para que la función la pueda manejar
correctamente.
Este efecto ocurre con cualquier cosa que sea de tamaño no definido, por ejemplo:
Un arreglo
Un string
Storage:
Hace referencia a todos los datos guardados permanentemente en la blockchain. ¿Pero
cuáles son estos datos? Las variables de nuestro contrato que hayan sido declaradas
en el scope global fuera de cualquier método (función del contrato), a esto se le
denomina el ESTADO de nuestro Smart Contract. Puedes entenderlo como los datos del
disco duro de tu ordenador, solo que están en la blockchain, esto es,
descentralizados en millones de discos duros u otros dispositivos de almacenamiento
persistente (nodos).
Data Location
Storage: Queda guardada dentro de la blockchain, siempre vamos a poder obtener
el valor almacenado, pues este nunca se va borrar. Memoria Persistente.
Memory (Modificable): Solo existe mientras se llama una función y no podemos
acceder de nuevo a el dato. Temporales. Costo menor al STORAGE
Calldata: Solo existe mientras se llama la función.
Por defecto las variables de estado se almacenan en el storage y los parámetros en
memory.
Gas y comisiones
El gas es una unidad de medida para el procesamiento de la EVM. Se mide en unidades
de gas, y es constante para las mismas operaciones.
gasPrice: Es la cantidad de ETH que pagamos por unidad de gas. Es decir, aunque
el gas sea constante, la demanda por ese gas puede subir el precio.
gasCost: Es la cantidad de unidades de gas que generó la ejecución
gasFee: Gas cost * Gas Price
Priority fee
A partir del EIP1559 , se realizaron cambios importantes al mercado de gas, y se
contempla el priority fee, que es el extra que menciona Sebastián, y es una propina
para el minero con la cuál se obtiene prioridad en la ejecución
Me queda la duda con el concepto de gas fee, en la clase se explica que la formula
para el gas total es: GasTotal = Gas x GasPrice + GasFee. Entiendo ademas que el
gas fee es la comisión que se le paga al minero y esto puede variar según el uso de
la red. Si esto es correcto el gasFee NO es GasCost * GasPrice. En la siguiente
página se ve como cambia el gas fee [Link]
Gas y comisiones
El gas es una unidad de medida para el procesamiento de la EVM. Se mide en unidades
de gas, y es constante para las mismas operaciones.
gasPrice: Es la cantidad de ETH que pagamos por unidad de gas. Es decir, aunque
el gas sea constante, la demanda por ese gas puede subir el precio.
gasCost: Es la cantidad de unidades de gas que generó la ejecución
gasFee: Gas cost * Gas Price
Priority fee
A partir del EIP1559 , se realizaron cambios importantes al mercado de gas, y se
contempla el priority fee, que es el extra que menciona Sebastián, y es una propina
para el minero con la cuál se obtiene prioridad en la ejecución
La fórmula que utiliza el profesor es una simplificación. Creo que los términos
utilizados igual no son los más correctos y eso generalmente es lo que causa
confusión.
Cuando hablamos de gasFee lo puedes interpretar de diferentes maneras
La cantidad de unidades de gas que costó. Este no es necesariamente ETH
La cantidad que le llega al minero. Este es REALMENTE el priority fee
La cantidad que el usuario paga en ETH. De este, una parte va al minero y el
otro se quema.
gasFee no es un término preciso porque tiene interpretaciones, de hecho no existe
en la EVM, lo correcto es:
En ETHEREUM con el EIP1559
BASE_FEE: Es el gasPrice del bloque. El EIP1559 sí establece un precio base
para el gas por bloque, que varía en base a la demanda. Este se quema
PRIORITY_FEE: Es el extra que se paga al minero por preferir tu transacción.
Este sí va al minero.
En cualquier otra EVM compatible blockchain sin EIP1559
GAS_PRICE: Cantidad de ether por unidad de gas.
Realmente utilizamos “fee” como una conveniencia para muchas cosas, como el
dashboard que compartiste. Pero formalmente no existe el término
Transferencia de ether desde un contrato
send: Envía un monto a una dirección y retorna false si la transferencia no se
realiza
transfer: Envía un monto y revierte si no se puede realizar
call: Esta es más complicada, pero básicamente realiza una llamada hacia una
dirección. Incluso se pueden llamar funciones de otro contrato si se le pasa un
address válido y la llamada dentro del parámetro data. No obstante, al ser un
mensaje, puede llevar ether, y por eso se usa para envíos. Retorna el resultado de
la función llamada (si es que fué el caso
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Transferencia {
constructor() payable {
function transferenciaPorSend(address destino,uint monto) public returns(bool)
{
bool salida = payable(destino).send(monto);
return salida;
}
function transferenciaPorTransfer(address destino, uint monto) public {
payable(destino).transfer(monto);
}
function transferenciaPorCall(address destino,uint monto) public returns(bool)
{
(bool salida, bytes memory respuesta) = [Link]{value:monto}("");
return salida;
}
}
Recibir ether desde un contrato
send Ether
|
[Link] esta vacia?
/ \
yes no
/ \
receive() existe? fallback()
/ \
yes no
/ \
receive() fallback()
Recibir Ether desde un contrato
Receive: Recibe el saldo de trasferencias sin parámetros.
FallBack: Recibe información adjunta a la trasferencia por medio de los
parámetros.
Función Payable: Se especifica el tipo payable a una función que puede recibir
trasferencias.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Recepcion {
//trasferencia limpia sin parametros, puede recibir saldos
//y poder ejecutar codigo cuando se recibe saldo de transferencia limpia
mapping(address => uint) balances;
uint public saldoEnviado;
receive() external payable {
balances[[Link]] += [Link];
}
//funcion para recibir parametros que no corresponden a ninguna funcion en
particular
fallback() external payable {
//Funcion que es capaz de recibir saldo, no quiere decir que siempre reciba
// saldo
function recibirSaldo(uint numero) public payable {
saldoEnviado = [Link];
uint monto =numero;
}
importaciones
LIBRERIAS
Manejo de dependencias y librerías
Importar una dependencia
Con la sentencia “import” podemos hacer referencia a un contrato que esté
definido en el mismo ámbito en el que estemos trabajando.
También podemos importar contratos que se encuentren en un repositorio o en un
paquete como npm.
Además de contratos podemos importar librerías que son similares a los
contratos, pero no contienen estado y solo brindan utilidad.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "@openzeppelin/contracts/utils/math/[Link]";
contract Importacion {
function sumarNumeros(uint numero1, uint numero2) public pure returns (uint) {
return [Link](numero1,numero2);
}
En el el caso de estar desarrollado tendríamos que tener instalado openzeppelin por
medio de npm.
En el caso de estar desarrollando en remix ya tenemos acceso a openzeppelin y
podemos importarlo directamente sin mayor problema.
En remix, cuidado al momento de hacer deploy y las referencias, el deploy siempre
buscara lo primero que encuentre en las referencias, para hacer deploy de nuestro
contrato debemos seleccionarlo
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "@openzeppelin/contracts/utils/math/[Link]";
contract Importacion {
function sumarNumeros(uint numero1, uint numero2) public pure returns (uint) {
return [Link](numero1,numero2);
}
HERENCIA
Hola, para aclarar que Solidity sí es un lenguaje orientado a objetos, en la
documentación oficial lo definen así:
Solidity is an object-oriented, high-level language for implementing smart
contracts. Smart contracts are programs which govern the behaviour of accounts
within the Ethereum state.
“No hay que reinvetar la rueda”
Utilizamos la Herencia para reutilizar codigo en nuevos contratos. Solidity no es
POO, pero se comporta similar. Solidity es orientado a contratos. Identificaremos
con la sentencia is. Si un contrato tiene un constructor con parametros, debemos
indicar que valores debe tomar ese constructor para poder derivarse.
Entonces, se busca generar una relacion entre contratos para reutilizar el codigo
mediante la Herencia. Por lo que la capacidad de agregar/modificar una funcion ya
escrita en el contrato anterior nos sera de mucha utilidad.
Las funciones virtuales son funciones definidas para que se puedan reescrbir por
las funciones override. Para esto debemos establecer una relacion de Herencia. Si
una funcion virtual no define implementacion, el contrato se convierte en un
contrato abstracto. Tambien hay contratos abstractos que usamos como moldes vacios
para usar en futuros contratos.
Las interfaces no van a tener codigo. su funcion es indicarnos un comportamiento
que queremos que tenga un contrato. Solo tiene declaraciones (definiciones de
funciones) sin codigo.
super (sentencia) nos sirve para hacer referencia a una funcion de clase
superior.
Ejemplo practico: Buscamos 2 funciones virtuales en Modificadores📗 e Interface📘
para colocar en nuestro archivo/contrato de Herencia 📕📘📗.
Vamos a tener que importar el directorio de los demas contratos, en este caso se
encuentran en la misma carpeta los contratos. Coloco los emojis de libros para
hacer referencia a un contrato, si hay varios libros es porque es una Herencia que
contiene otros contratos.
/ SPDX-Licence-Identifier: UNLICENSED
pragma solidity >=0.7.0 < 0.9.0;
import "./[Link]";
import "./[Link]";
contract Herencia is Suma, Modificadores {
constructor(string memory nombreNuevo) Modificadores(nombreNuevo) {
function sumar(uint numero1, uint numero2) public override EsOwner() view
returns(uint) {
return numero1 + numero2;
}
}
Polimorfismo
Capacidad de poder utilizar contratos derivados en estructuras superiores.
Polimorfismo es una propiedad de la POO que permite (a nivel general digamos)
enviar mensajes iguales a objetos de diferentes tipos.
En limpio: tus objetos deben de “saber” responder al mensaje que les estás
enviando, esta es la propiedad polimórfica.
No tiene nada qué ver con contratos ni nada por el estilo, es puramente un tema de
objetos.
Qué es un token
n token es un objeto físico o digital que tiene valor en cierto contexto o para
U
determinada comunidad, aunque su propia materialidad no contenga ese valor en sí.
Las fichas de casino, por ejemplo, son solo pedazos de plástico de distintos
colores, pero representan cantidades de dinero. Algunas, hasta millones de dólares,
aunque fabricar una de ellas cueste apenas centavos.
Eso hacen los tokens: representan otra cosa, están en su lugar. ¿Por qué? Hay
muchos motivos: la comodidad, la seguridad, la facilidad de transportarlos o
transferirlos.
En el mundo cripto, los tokens se generan a partir de piezas de código de
programación, en formato de contratos inteligentes que corren sobre la blockchain.
El smart contract describe cómo funciona cada token. La base de datos lleva el
registro de cuántos tiene cada quien. Y los usuarios pueden enviárselos entre sí
como forma de transferirse valor.
ERC-20
Representa a los tokens fungibles
Solo define su Interface
Existen mas estándares pero mantienen compatibilidad con el ERC-20
ERC-20 OpenZeppelin
ERC-721
Representa a los tokens no fungibles. NFT
Solo define su Interface
Tienen un identificador único conocido como tokenId.
ERC-721 OpenZeppelin
[Link]
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/[Link]";
contract TokenFungible is ERC20("TokenFungible", "TF") {
//Funcion mint es la que emite los tokens y pide una direccion y una cantidad
constructor() {
_mint([Link], 1000);
}
OTRO EJEMPLO
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "@openzeppelin/contracts/token/ERC721/[Link]";
contract TokenNoFungible is ERC721("TokenNoFungible","TNF") {
//Funcion mint es la que emite los tokens y pide una direccion y un
identificador
constructor() {
//tener la precaucion de siempre tener un ID que no se repita, unico
_mint([Link], 1);
}
Application Binary Interface (ABI)
ABI
Application Binary Interface
Es una interface que nos detalla que definiciones tiene el contrato y sus
funciones, sin conocer su implementacion.
Nos permite saber la forma que tiene un contrato para poder interactuar con las
funciones.
ABI se presenta en formato JSON
Herramientas que gestionan el ABI
HardHat
Truffle