Solidity en 15 minutos
Published: 2023-02-11 22:38:58

---
title: Solidity en 15 minutos
published: true
description: 
tags: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vduiw0cmu1m9m290jl7r.png
---

{% youtube SAQ5Cvt_ePg %}

## Introducción a Solidity

* Solidity es el lenguaje más popular para Contratos Inteligentes
* Solidity está inspirado en Javascript, C++ y Python
* Solidity fue propuesto en 2014 por Gavin Wood, fue desarrollado por un equipo liderado para Christian Reitwiessner. Su primera versión estable fue lanzada en 2018
* Solidity tiene muy buen soporte por parte de su comunidad

## Compiladores de Solidity

Mi recomendación será que inicies con el [Remix IDE](https://remix.ethereum.org/) donde puedes compilar, lanzar e interactuar con contratos desde el browser sin instalar nada adicional.

Si deseas compilar un programa en solidity desde la terminal puedes instalar `solc` desde `npm`.

```bash
npm install -g solc
solcjs --version
solcjs --bin  MyContract.sol
```

Cuando estés listo para un ambiente de programación que te ayude a largo plazo te recomiendo [Hardhat](https://hardhat.org/), [Truffle](https://trufflesuite.com/) o [Foundry](https://book.getfoundry.sh/). Los tres son muy buenas opciones.

## Obtener fondos de prueba en metamask

Una vez descargada la [billetera de metamask](https://metamask.io/), mi recomendación es activar los testnets para poder acceder a Sepolia Testnet, una vez hecho eso puedes obtener fondos de manera gratuita desde el [Sepolia Faucet](https://sepoliafaucet.com/).

## "Hola Mundo!" en Solidity

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

contract HelloWorld {
    string hello = "Hola Mundo!";

    function setHello(string memory hello_) public
    {
        hello = hello_;
    }

    function getHello() public view returns (string memory)
    {
        return hello;
    }
}
```

### Licencia

La primera línea del contrato ejemplo es un comentario donde se coloca la licencia del Código. Este comentario es opcional pero te recomiendo agregar la licencia MIT que permite a los demás usar tu código con cualquier fin siempre y cuando te mencionen.

```solidity
// SPDX-License-Identifier: MIT
```

### Versión

La segunda línea es la versión de solidity, en este caso estamos usando la `0.8.19` que es la más nueva a la fecha que se escribió este artículo.

```solidity
pragma solidity 0.8.19;
```

## Declarar Variables

Solidity es _fuertemente tipeado_, es decir que al declarar una variable debes colocar su tipo.

```solidity
uint number = 150;
uint pi = 3.141 ether;
string memory name = "Filosofia Codigo is great";
string[] studentNames = ["Pedro", "Ana", "Juan", "Luisa"];
bool isSolidityAwesome = true;
```

## Tipos de datos en Solidity

A continuación mostramos los tipos de datos en Solidity

* uint

Uint se refiere a "unsigned integer" o entero sin signo. Por defecto se declara como un entero de 256 bits pero se puede definir el tamaño para ahorrar gas. El tamaño puede ser cualquier múltiplo de 8 desde `uint8` hasta `uint256`.

```solidity
uint num1 = 456;
uint16 num2 = 3;
uint num2 = 1235.56 ether;
```

Solidity no soporta puntos flotantes pero tiene las palabras reservadas `ether` y `wgei` son unidades de medida que representan `10¹⁸` y `10⁹` respectivamente. `wei` es la unidad mínima y la que utilizamos por defecto. Es decir que `1000000000000000000 wei = 1 ether`.

* int

Para represntar número con signo podemos usar int.

```solidity
int num1 = -234;
int num2 = 432;
int num3 = -5.7 ether;
```

* Strings

Colecciones de caracteres. Son bastante usadas para guardar información que sea fácil de leer para usuarios.

```solidity
string name = "Welcome to Solidity";
```

* Address

Representa una dirección de una billetera o contrato en el blockchain.

```solidity
address owner = 0xb6F5414bAb8d5ad8F33E37591C02f7284E974FcB;
```

* Mapas o mapping

Representan pares de LLaves y Valores. Son una manera muy eficiente de guardar leer colecciones de datos.

```solidity
mapping(string account => uint balance) balances;
balances["Ana"] = 50;
balances["Juan"] = 100;
```

* Arreglos

Los usamos para guardar colecciones de datos. Úsalos únicamente para datos rígidos, que no cambien mucho. Si deseas una colección más dinámica usa los Mapas para ahorrar gas.

```solidity
uint[] myArray = [100, 50, 300];
```

* Booleanos

Usados para representar datos del estilo verdadero o falso.

```solidity
bool valid = true
bool invalid = false
```

## Operar Strings en Solidity

### Comparar Strings

A diferencia de otros lenguajes, en Solidity no podemos comparar dos `strings` usando el operador `==`. Para hacerlo debemos primero convertirlas a sus hashes respectivos y luego comparar los resultados.

```solidity
string memory a = "Hola!";
string memory b = "Hola!";
bool stringsAreEqual = keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
```

### Concatenar de Strings

```solidity
string memory a = "Hola ";
string memory b = "Mundo!";
string memory holaMundo = string.concat(a,b);
```

### ¿Cuándo usar memory en Solidity?

Cuando una String se declara en memoria durante el tiempo de ejecución colocamos la palabra `memory`. Esto es cuando declaramos una variable como parámetro o dentro de una función. Únicamente las Strings declaradas como variables de estado de un contrato no llevan esta palabra reservada, esto significa que son guardadas on-chain y no en memoria.

```solidity
contract ExampleStrings {
    string stateVariable;
    function exampleFunction(string memory parameterVariable) public {
      string memory scopeVariable;
    }
}
```

## Enum en solidity

Los enums nos permiten crear nuestros propios tipos de variables para hacer el código más legible. Funcionan muy similar a C donde los elementos del Enum pueden ser representados por enteros donde el primer elemento es 0;

```solidity
enum Color { Red, Green, Blue }
Color color = Color.Blue;
```

## Struct en solidity

Las Structs nos permiten crear nuevos tipos de variables que agrupan diferentes valores.

```solidity
struct Voter {
    uint weight;
    bool voted;
    uint vote;
}
Voter voter = Voter(10, true, 4);
```

## Mapas en Solidity

### Declarar un Mapa

Los mapas pueden ser una combinación de diferentes tipos de pares. El valor asociado con una llave puede ser otro mapa.

```solidity
mapping(address account => uint balance) balances;
mapping(uint256 nftId => address owner) nftOwner;
mapping(uint256 => mapping(string => bool)) nestedExample;
```

### Asignar un valor

```solidity
balances[0xb6F5414bAb8d5ad8F33E37591C02f7284E974FcB] = 10 ether;
```

### Leer un valor

```solidity
address owner = nftOwner[10];
```

### Cómo borrar un elemento de un Mapa

Técnicamente no existe una función para borrar un elemento. Pero podemos regresarlo a su valor inicial que es `0` indicando así que el elemento no existe.

```solidity
balances[10] = 0;
names[10] = "";
addresses[10] = address(0);
```

## Funciones

En Solidity existen diferentes tipos de funciones.

* Funciones de escritura

Toda que escribe o cambia un valor en el blockchain, es decir que cambia su estado, debe pagar gas.

```solidity
uint balance;

function setBalance(uint balance_) public {
    balance = balance_;
}
```

* Funciones payable en Solidity

Colocamos la palabra reservada `payable` en una función que sea capaz de recibir ETH. La cantidad de ETH recibida quedará almacenada en la variable reservada `msg.value`.

```solidity
uint public totalPayed;

function payToContract() public payable
{
    totalPayed += msg.value;
}
```

* Funciones view en Solidity

Colocamos la palabra reservada `view` en una función cuando esta no escribe nada en el blockchain, cuando no cambia el estado.

```solidity
uint balance;

function getBalance() public view returns(uint) {
    return balance;
}
```

* Funciones pure en Solidity

Colocamos la palabra reservada `pure` en una función cuando esta no escribe ni lee el estado del blockchain.

```solidity
function getPi() public pure returns(uint) {
    return 3.14 ether;
}
```

### Visibilidad de funciones en solidity

* Funciones public en Solidity

Para que nuestra función puede ser llamada desde afuera del contrato debemos agregar la palabra reservada `public`.

```solidity
string name;
function getName() public view returns(string memory) {
    return name;
}
```

* Funciones internal y private en Solidity

Las funciones `internal` se pueden acceder únicamente desde adentro del Smart Contract. Es el mismo caso con las funciones `private` pero estas no serán heredadas en contratos hijos.

```solidity
function sum(uint a, uint b) internal pure returns(uint) {
    return a + b;
}
```

## If/Else en Solidity

```solidity
function compare(uint a, uint b) public pure returns(int) {
    if(a > b)
    {
        return 1;
    } else if(a == b)
    {
        return 0;
    } else
    {
        return -1;
    }
}
```

## Cíclo While en Solidity

```solidity
uint num = 0;
while(num < 10)
{
  mintNFT();
  num += 1;
}
```

## Cíclo For en Solidity

```solidity
for(uint i=0; i<10; i++)
{
  mintNFT();
}
```

## Palabras reservadas en Solidity

* msg.send

Dirección de quien envió la transacción.

```solidity
address sender = msg.sender;
```

* msg.value

Cantidad de wei enviada al contrato.

```solidity
uint weiSent = msg.value;
```

* block.timestamp

Epoch en segundos del bloque que ha sido minado mas recientemente. Usa el formato Unix.

```solidity
uint currentEpoch = block.timestamp;
```

* block.number

Número de bloque que fue minado mas recientemente.

```solidity
uint blockNumber = block.number;
```

Estas son las palabras reservadas más comunes pero en [este enlace](https://docs.soliditylang.org/en/v0.8.19/cheatsheet.html) puedes ver la lista completa.

## ¿Cómo agregar comentarios en Solidity?

Puedes agregar comentarios de dos maneras.

### Comentarios de una línea

```solidity
// Este es un comentario de una línea.
```

### Comentarios multilínea

```solditiy
/*
Este
es
multilínea
*/
```

## Event y Emit en Solidity

Los eventos pueden emitirse en cualquier función de tipo escritura y pueden detallar los cambios que ocurrieron en las transacciones. Usamos los eventos para que los usuarios finales puedan ver el historial de un contrato inteligente en plataformas como Etherscan o Blocscout. Y recientemente se utilizan estos eventos para organizar información y poder hacer búsquedas con ayuda de proyectos como TheGraph.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

contract HelloWorld {
    string hello = "Hola Mundo!";

    event HelloValueChanged(address sender, string newValue);

    function setHello(string memory hello_) public
    {
        hello = hello_;
        emit HelloValueChanged(msg.sender, hello);
    }
}
```

## ¿Qué es modifier en Solidity?

Los modifiers nos permiten agregar código en funciones para hacer el código más legible y menos repetitivo.

```solidity
modifier checkBalance(uint decreaseAmount) {
    require(balance >= decreaseAmount, "Not enough balance.");
    _;
}

function decreaseBalance(uint balance_) internal checkBalance(balance_) {
    balance -= balance;
}
```

## Manejo de errores en Solidity

### ¿Qué es revert en Solidity?

Revert detiene la ejecución de la transacción y revierte al estado anterior, es decir que deshace los cambios que se hicieron. La usamos cuando se encuentra un error o cuando las condiciones para ejecutar una función no se cumplen (por ejemplo, si alguien desea retirar antes que se cumpla un deadline en un contrato estilo timelock. En general el `revert()` es bastante útil pero usualmente preferimos usar `require` que veremos a continuación.

```solidity
if(balance == 0)
  revert();
```

### ¿Qué es require en Solidity?

El `require` revierte la transacción si no se cumple la condición en su primer parámetro. Es similar al `revert()` pero adicionalmente devuelve un mensaje de error que luego puede ser leído por el usuario, ya sea on-chain o en herramientas como etherscan o blockscout.

```solidity
require(balance > 0, "Not enough balance");
```

### ¿Qué es assert en Solidity?

El assert devuelve un error cuando no se cumple la condición enviada por parámetro. A diferencia del `revert()` y `require`, el `assert` no devuelve un mensaje fácil de leer para los usuarios así que es una función pensada para hacer pruebas internas. En teoría, un error de tipo `assert` jamás debería ser encontrado por un usuario final. Únicamente debería ser encontrado por herramientas de pruebas como unit tests, fuzzing  u otras herramientas de pruebas estáticas. Si estás en duda, no utilices `assert`, mejor utiliza `require` para hacer un contrato seguro y fácil de operar. Personalmente, pienso que `assert` es un lujo ya que incurre en costos de gas a cambio de útilidad mínima.

```solidity
assert(balance >= totalSupply);
```

## Interfaces en Solidity

Al implementar una interfaz en un contrato con la palabra reservada `is` obligamos al contrato a implementar todos los métodos de la interfaz. Como programadores, esto nos ayuda a que no olvidemos declarar todos los métodos. Y también ayuda a hacer el código más fácil de leer para el público en general.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

interface IPersonalProfile
{
    function getName() external returns(string memory);
    function getWallet() external returns(address);
}

contract PersonalProfile is IPersonalProfile{
    string name;
    address wallet;

    constructor(string memory name_, address wallet_)
    {
        name = name_;
        wallet = wallet_;
    }

    function getName() external view returns(string memory)
    {
        return name;
    }

    function getWallet() external view returns(address)
    {
        return wallet;
    }
}
```

### Interoperabilidad de contratos

La interoperabilidad entre contratos es cuando un contrato ejecuta funciones en otro contrato. La interoperabilidad es parte de la naturaleza del blockchain pues es un sistema abierto y descentralizado. Las interfaces nos ayudan a hacer esto posible.

Supongamos que tenemos lanzado en el blockchain el siguiente contrato.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

contract ContractA
{
    string variable;
    function writeFunction(string memory param) public
    {
        variable = param;
    }

    function readFunction() public view returns(string memory)
    {
        return variable;
    }
}
```

Podemos operar este contrato desde otro contrato si tenemos la interfaz y el address donde fue lanzado. En este caso lo enviamos desde el constructor pero puede ser el parámetro de una función o un valor estático.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

interface IContractA
{
    function writeFunction(string memory param) external;
    function readFunction() external view returns(string memory);
}

contract ContractB
{
    IContractA contractA;
    constructor(address contractAAddress)
    {
        contractA = IContractA(contractAAddress);
    }

    function writeInteroperability(string memory param) public
    {
        contractA.writeFunction(param);
    }

    function readInteroperability() public view returns(string memory)
    {
        return contractA.readFunction();
    }
}
```

## Herencia en Solidity

Los contratos en Solidity pueden implementar herencia de una manera muy similar a la de cualquier otro lenguaje orientado a objetos. Para indicar que se está heredando usamos la palabra reservada `is`. También podemos hacer uso de las palabras reservadas `virtual` y `override` para sobreescribir métodos.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract Animal
{
    string name;
    string color;

    constructor(string memory name_, string memory color_)
    {
        name = name_;
        color = color_;
    }

    function speak() public pure virtual returns(string memory)
    {
        return "Ggggg";
    }
}

contract Cat is Animal
{
    constructor(string memory name_, string memory color_) Animal(name_, color_)
    {
    }

    function speak() public pure override returns(string memory)
    {
        return "Miau";
    }

    function walk() public pure returns(string memory)
    {
        return "Puedo caminar en cuatro patas.";
    }
}
```

## Librerías en Solidity

Las librerías nos ayudan a mantener nuestro código ordenado y menos repetitivo. Las librerías no pueden almacenar variables de estado, no se pueden heredar y se limitan a ofrecer funciones de tipo lectura.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

library ArithmeticLibrary
{
    function add(uint a, uint b) public pure returns(uint) {
        return a + b;
    }

    function sub(uint a, uint b) public pure returns(uint) {
        return a - b;
    }
}

contract Calculator {
    using ArithmeticLibrary for uint;
    
    function getSum(uint firstNumber, uint secondNumber) public pure returns(uint) {
        return firstNumber.add(secondNumber);
    }

    function getSub(uint firstNumber, uint secondNumber) public pure returns(uint) {
        return firstNumber.sub(secondNumber);
    }
}
```

## Importar librerías y contratos en Solidity

Podemos importar librerías y contratos con la palabra reservada `import`. Le podemos proveer una dirección relativa a otro archivo `.sol`. En caso que estemos usando Remix, podemos proveerle un link directo o un archivo almacenado en una librería de npm. Las importar archivos nos ayuda a mantener nuestro código más ordenado y más seguro siempre y cuando usemos código de fuentes confiables, auditadas y probadas a través del tiempo.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract SimpleToken is ERC20 {
    constructor(
        string memory name,
        string memory symbol,
        uint256 initialSupply
    ) ERC20(name, symbol) {
        _mint(msg.sender, initialSupply * 1 ether);
    }
}
```

**¡Gracias por ver este tutorial!**

Sígueme en dev.to y en [Youtube](https://www.youtube.com/channel/UCNRB4tgwp09z4391JRjEsRA) para todo lo relacionado al desarrollo en Blockchain en Español.