Solidity 2
Solidity 2
Solidity 2
https://solidity-by-example.org/call/
platzi.com/celo construyendo en Web3
https://docs.opensea.io/docs/metadata-standards
https://docs.soliditylang.org/en/v0.8.14/
https://www.tutorialspoint.com//solidity/index.htm
https://ethernaut.openzeppelin.com/
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/
token/ERC20/ERC20.sol
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/
token/ERC721/ERC721.sol
https://web3js.readthedocs.io/en/v1.2.11/web3-eth-abi.html#eth-abi
https://docs.ethers.io/v5/api/utils/abi/
sebastian
https://www.blockchainacademy.cl/enrol/index.php?id=10
https://twitter.com/sebaleoperez
}
CURSO
https://platzi.com/cursos/intro-dapps/
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.
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 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).
//SPDX-License-Identifier: GPL-3.0
contract Estructura {
int cantidad;
uint cantidadSinSigno;
address direccion;
bool firmado;
Structs
arreglos
override(Arreglos)
// Arreglos dinámicos
<type>[] <visibility> <name>;
uint[] data;
data.push(10);
data.push(20);
data.push(30);
// [10, 20, 30]
data.pop();
// [10, 20]
contract Clase {
struct Alumno {
string nombre;
uint documento;
}
Alumno [] public alumnos;
constructor() {
alumnos.push(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)
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 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
}
contract Saldo {
constructor() {
estadoDelContrato = Estado.Iniciado;
balance[msg.sender] = 1000;
estadoDelContrato = Estado.Finalizado;
}
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 {
constructor(bool condicion) {
if (condicion) {
resultado = "Condicion True";
}
else {
resultado = "Condicion False";
}
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.
contract Eventos {
constructor(bool condicion) {
if (condicion) {
resultado = "Condicion True";
}
else {
resultado = "Condicion False";
}
emit NotificacionDeCondicion(condicion);
Se usan para:
FUNCIONES
Funciones
Convenciones no obligatorias
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.
MODIFICADORES
Los modificadores son funciones especiales por el usuario y que se añaden a otra
función para envolver su funcionamiento
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 (msg.sender != owner) revert("Solo el dueño del contrato puede
modificarlo.");
_;
}
EJEMPLO DE MODIFICADORES
// SPDX-License-Identifier: GPL-3.0
contract Modificadores {
//qureremos restrir que solo el que hizo el deploy del contrato
constructor() {
owner = msg.sender;
}
modifier EsOwner() {
if (msg.sender!= owner) revert();
_;
}
}
Manejo de errores
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 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 ()
Tipos de almacenamiento
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:
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.
Gas y comisiones
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
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 https://crypto.com/defi/dashboard/gas-fees
Gas y comisiones
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
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.
Realmente utilizamos “fee” como una conveniencia para muchas cosas, como el
dashboard que compartiste. Pero formalmente no existe el término
// SPDX-License-Identifier: GPL-3.0
contract Transferencia {
constructor() payable {
send Ether
|
msg.data esta vacia?
/ \
yes no
/ \
receive() existe? fallback()
/ \
yes no
/ \
receive() fallback()
// SPDX-License-Identifier: GPL-3.0
contract Recepcion {
//Funcion que es capaz de recibir saldo, no quiere decir que siempre reciba
// saldo
}
importaciones
LIBRERIAS
Manejo de dependencias y librerías
// SPDX-License-Identifier: GPL-3.0
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Importacion {
// SPDX-License-Identifier: GPL-3.0
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract Importacion {
HERENCIA
Hola, para aclarar que Solidity sí es un lenguaje orientado a objetos, en la
documentación oficial lo definen así:
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.
super (sentencia) nos sirve para hacer referencia a una funcion de clase
superior.
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
import "./Interface.sol";
import "./Modificadores.sol";
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.
ERC-20
ERC-20 OpenZeppelin
ERC-721
ERC-721 OpenZeppelin
TokenFungible.sol
// SPDX-License-Identifier: GPL-3.0
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TokenFungible is ERC20("TokenFungible", "TF") {
//Funcion mint es la que emite los tokens y pide una direccion y una cantidad
constructor() {
_mint(msg.sender, 1000);
}
OTRO EJEMPLO
// SPDX-License-Identifier: GPL-3.0
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
ABI
HardHat
Truffle