Full Code of joaneeet7/Solidity for AI

main 04fcf52a21db cached
59 files
212.7 KB
60.2k tokens
1 requests
Download .txt
Showing preview only (234K chars total). Download the full file or copy to clipboard to get everything.
Repository: joaneeet7/Solidity
Branch: main
Commit: 04fcf52a21db
Files: 59
Total size: 212.7 KB

Directory structure:
gitextract_nsm2lemb/

├── .gitignore
├── BLOQUE 1 - Conceptos básicos de Solidity/
│   ├── Tema 1 - Primeros pasos/
│   │   ├── ERC20.sol
│   │   ├── SafeMath.sol
│   │   └── conceptos_basicos.sol
│   ├── Tema 10 - Fábrica de Smart Contracts/
│   │   └── factory.sol
│   ├── Tema 2 - Propiedades transacciones y bloques/
│   │   ├── funciones_globales.sol
│   │   └── keccak256.sol
│   ├── Tema 3 - Tipos de variables y operadores/
│   │   ├── Modificadores.sol
│   │   ├── Operadores.sol
│   │   ├── casteo_variables.sol
│   │   ├── comparar_strings.sol
│   │   ├── enum.sol
│   │   ├── mas_variables.sol
│   │   ├── unidades_tiempo.sol
│   │   └── variables_enteras.sol
│   ├── Tema 4 - Estructuras de datos/
│   │   ├── Estructuras.sol
│   │   ├── arrays.sol
│   │   └── mappings.sol
│   ├── Tema 5 - Funciones/
│   │   ├── causas_beneficas.sol
│   │   ├── eventos.sol
│   │   ├── funciones.sol
│   │   ├── modificadores.sol
│   │   └── returns.sol
│   ├── Tema 6 - Bucles y condicionales/
│   │   ├── bucle_for.sol
│   │   ├── bucle_while.sol
│   │   └── sentencia_if.sol
│   ├── Tema 7 - Interactuando con otros Smart Contracts/
│   │   ├── Banco.sol
│   │   ├── Cliente.sol
│   │   ├── herencia.sol
│   │   └── librerias.sol
│   ├── Tema 8 - Funciones avanzadas/
│   │   ├── internal_external.sol
│   │   ├── modifier.sol
│   │   └── require.sol
│   └── Tema 9 - SafeMath/
│       ├── SafeMath.sol
│       ├── SafeMath_comentada.sol
│       └── ejemplo_uso.sol
├── BLOQUE 2 - Proyectos reales con Smart Contracts/
│   ├── Creación y uso de un Token ERC-20/
│   │   ├── ERC20.sol
│   │   └── SafeMath.sol
│   ├── DISNEY/
│   │   ├── ERC20.sol
│   │   ├── SafeMath.sol
│   │   └── disney.sol
│   ├── Evaluaciones universitarias con un Smart Contract/
│   │   └── notas.sol
│   ├── LOTERIA/
│   │   ├── ERC20.sol
│   │   ├── SafeMath.sol
│   │   └── loteria.sol
│   ├── OMS/
│   │   └── oms.sol
│   └── VOTACION/
│       ├── votacion.sol
│       └── votacion_tarea.sol
├── BLOQUE 3 - Proyecto final de curso/
│   └── PROYECTO FINAL - Servicio de telemedicina/
│       ├── ERC20.sol
│       ├── MedicalInsurance.sol
│       ├── OperacionesBasicas.sol
│       └── SafeMath.sol
├── BLOQUE 4 - Creación de una Blockchain con Python/
│   └── blockchain.ipynb
├── BLOQUE 5 - Creación de una Criptomoneda con Python/
│   ├── criptomoneda_5000.ipynb
│   ├── criptomoneda_5001.ipynb
│   ├── criptomoneda_5002.ipynb
│   ├── nodes.json
│   └── transaction.json
└── README.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store


================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 1 - Primeros pasos/ERC20.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 < 0.7.0;
pragma experimental ABIEncoderV2;
import "./SafeMath.sol";



//Juan Gabriel ---> 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
//Juan Amengual ---> 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
//María Santos ---> 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db

//Interface de nuestro token ERC20
interface IERC20{
    //Devuelve la cantidad de tokens en existencia
    function totalSupply() external view returns (uint256);

    //Devuelve la cantidad de rokens para una dirección indicada por parámetro
    function balanceOf(address account) external view returns (uint256);

    //Devuelve el número de token que el spender podrá gastar en nombre del propietario (owner)
    function allowance(address owner, address spender) external view returns (uint256);

    //Devuelve un valor booleano resultado de la operación indicada
    function transfer(address recipient, uint256 amount) external returns (bool);

    //Devuelve un valor booleano con el resultado de la operación de gasto
    function approve(address spender, uint256 amount) external returns (bool);

    //Devuelve un valor booleano con el resultado de la operación de paso de una cantidad de tokens usando el método allowance()
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);



    //Evento que se debe emitir cuando una cantidad de tokens pase de un origen a un destino
    event Transfer(address indexed from, address indexed to, uint256 value);

    //Evento que se debe emitir cuando se establece una asignación con el mmétodo allowance()
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

//Implementación de las funciones del token ERC20
contract ERC20Basic is IERC20{

    string public constant name = "ERC20BlockchainAZ";
    string public constant symbol = "ERC";
    uint8 public constant decimals = 18;

    event Transfer(address indexed from, address indexed to, uint256 tokens);
    event Approval(address indexed owner, address indexed spender, uint256 tokens);


    using SafeMath for uint256;

    mapping (address => uint) balances;
    mapping (address => mapping (address => uint)) allowed;
    uint256 totalSupply_;

    constructor (uint256 initialSupply) public{
        totalSupply_ = initialSupply;
        balances[msg.sender] = totalSupply_;
    }


    function totalSupply() public override view returns (uint256){
        return totalSupply_;
    }

    function increaseTotalSupply(uint newTokensAmount) public {
        totalSupply_ += newTokensAmount;
        balances[msg.sender] += newTokensAmount;
    }

    function balanceOf(address tokenOwner) public override view returns (uint256){
        return balances[tokenOwner];
    }

    function allowance(address owner, address delegate) public override view returns (uint256){
        return allowed[owner][delegate];
    }

    function transfer(address recipient, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        balances[recipient] = balances[recipient].add(numTokens);
        emit Transfer(msg.sender, recipient, numTokens);
        return true;
    }

    function approve(address delegate, uint256 numTokens) public override returns (bool){
        allowed[msg.sender][delegate] = numTokens;
        emit Approval(msg.sender, delegate, numTokens);
        return true;
    }

    function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[owner]);
        require(numTokens <= allowed[owner][msg.sender]);

        balances[owner] = balances[owner].sub(numTokens);
        allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(owner, buyer, numTokens);
        return true;
    }
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 1 - Primeros pasos/SafeMath.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// Implementacion de la libreria SafeMath para realizar las operaciones de manera segura
// Fuente: "https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be"

library SafeMath{
    // Restas
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }
    
    // Sumas
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
    
    // Multiplicacion
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
}


================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 1 - Primeros pasos/conceptos_basicos.sol
================================================
// SPDX-License-Identifier: MIT
//Inidicamos la version
pragma solidity >=0.4.4 <0.7.0;
//Importar el archivo ERC20.sol que está en nuestro directorio de trabajo
import "./ERC20.sol";

// Nuestro primer contrato
contract PrimerContrato{
    
    //En esta variable se encuentra la direccion de la persona que despliega el contrato
    address owner;
    ERC20Basic token;
    
    /*
    Guardamos en la variable owner la direccion de la persona que despliega el contrato
    inicializamos el numero de tokens
    */
    constructor() public{
        owner =msg.sender;
        token = new ERC20Basic(1000);
    }
    
}




================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 10 - Fábrica de Smart Contracts/factory.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.9.0;
pragma experimental ABIEncoderV2;

contract SmartContract1 {
    
    // Almacenamiento de la informacion del Factory
    mapping (address => address) public MiContratoPersonal;
    
    function Factory() public {
        address direccion_nuevo_contrato = address (new SmartContract2(msg.sender)); 
        MiContratoPersonal[msg.sender] = direccion_nuevo_contrato;
    }
}

contract SmartContract2 {
    
    address public owner;

    constructor (address _direccion) public {
        owner = _direccion;
    }
    
}



================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 2 - Propiedades transacciones y bloques/funciones_globales.sol
================================================
// SPDX-License-Identifier: MIT
//Indicamos la version
pragma solidity >=0.4.4 <0.7.0;

contract funciones_globales{
    
    //Funcion msg.sender
    function MsgSender() public view returns(address){
        return msg.sender;
    }
    
    //funcion now
    function Now() public view returns(uint){
        return now;
    }
    
    //funcion block.coinbase
    function BlockCoinbase() public view returns(address){
        return block.coinbase;
    }
    
    //funcion block.difficulty
    function BlockDifficulty() public view returns(uint){
        return block.difficulty;
    }
    
    //funcion block.number 
    function BlockNumber() public view returns(uint){
        return block.number;
    }
    
    //Funcion msg.sig 
    function MsgSig() public view returns(bytes4){
        return msg.sig;
    }
    
    //funcion tx.gaspricev
    function txGasPrice() public view returns(uint){
        return tx.gasprice;
    }
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 2 - Propiedades transacciones y bloques/keccak256.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract hash{
    
    //Computo del hash de un string
    function calcularHash(string memory _cadena) public pure returns(bytes32){
        return keccak256(abi.encodePacked(_cadena));
    }
    
    //Computo del hash de un string, un entero y una direccion
    function calcularHash2(string memory _cadena, uint _k, address _direccion) public pure returns(bytes32){
        return keccak256(abi.encodePacked(_cadena, _k, _direccion));
    }
    //Computo del hash de un string, un entero y una direccion mas otro string y entero que no estan
    //dentro de una variable
    function calcularHash3(string memory _cadena, uint _k, address _direccion) public pure returns(bytes32){
        return keccak256(abi.encodePacked(_cadena, _k, _direccion, "hola", uint(2)));
    }
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/Modificadores.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract public_private_internal{
    
    //Modificador public 
    uint public mi_entero = 45;
    string public mi_string = "Joan";
    address public owner;
    
    constructor() public{
        owner = msg.sender;
    }
    
    //Modificador private
    uint private mi_entero_privado = 10;
    bool private flag =true;
    
    function test(uint _k) public{
        mi_entero_privado = _k;
    }
    
    //Modificador internal
    bytes32 internal hash = keccak256(abi.encodePacked("hola"));
    address internal direccion = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
    
    
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/Operadores.sol
================================================
// SPDX-License-Identifier: MIT
//Indicando la version
pragma solidity >=0.4.4 <0.7.0;

contract Operadores{
    
    // Operadores matematicos
    uint a = 32;
    uint b = 4;
    
    uint public suma = a+b;
    uint public resta = a-b;
    uint public division = a/b;
    uint public multiplicacion = a*b;
    uint public residuo = a%b;
    uint public exponenciacion = a**b;
    
    //Comparar enteros
    uint c = 3;
    uint d = 3;
    
    
    bool public test_1 = a>b;
    bool public test_2 = a<b;
    bool public test_3 = c==d;
    bool public test_4 = a==d;
    bool public test_5 = a!=b;
    bool public test_6 = a>=b;
    
    //Operadores booleanos
    
    //Criterio de divisibilidad entre 5: si el numero termina en 0 o en 5
    
    function divisibilidad(uint _k) public pure returns(bool){
        
        uint ultima_cifra = _k%10;
        
        if((ultima_cifra==0)||(ultima_cifra==5)){
            return true;
        }else{
            return false;
        }
        
    }
    
    function divisibilidadV2(uint _k) public pure returns(bool){
        
        uint ultima_cifra = _k%10;
        
        if((ultima_cifra!=0)&&(ultima_cifra!=5)){
            return false;
        }else{
            return true;
        }
    }
    
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/casteo_variables.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;

contract casteo{
    
    //Ejemplos de casteo de variables
    
    uint8 entero_8_bits= 42;
    uint64 entero_64_bits = 60000;
    uint entero_256_bits = 1000000;
    int16 entero_16_bits = 156;
    int120 entero_120_bits = 900000;
    int entero = 5000000;
    
    //Casteo de las variables
    uint64 public casteo_1 = uint64(entero_8_bits); 
    uint64 public casteo_2 = uint64(entero_256_bits);
    uint8 public casteo_3 = uint8(entero_16_bits);
    int public  casteo_4 = int(entero_120_bits);
    int public casteo_5 = int(entero_256_bits);
    
    
    function convertir(uint8 _k) public pure returns(uint64){
        return uint64(_k);
    }
    
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/comparar_strings.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract compararStrings{
    
    function Comparar(string memory _j ,string memory _i) public pure returns(bool){
        
        bytes32 hash_i = keccak256(abi.encodePacked(_i));
        bytes32 hash_j = keccak256(abi.encodePacked(_j));
        
        if(hash_i == hash_j){
            return true;
        }else{
            return false;
        }
        
    }
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/enum.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;

contract Ejemplos_enumeraciones{
    
    //Enumeracion de interruptor
    enum estado {ON, OFF}
    
    //Variable de tipo enum (estado)
    estado state;
    
    function encender() public{
        state = estado.ON;
    }
    
    function fijarEstado(uint _k) public {
        state = estado(_k);
    }
    
    function Estado() public view returns(estado){
        return state;
    }
    
    
    //Enumeracion de direcciones
    enum direcciones {ARRIBA, ABAJO, DERECHA, IZQUIERDA}
    
    //Varibale de tipo enum (direcciones)
    direcciones direccion = direcciones.ARRIBA;
    
    function arriba() public{
        direccion = direcciones.ARRIBA;
    }
    
    function abajo() public{
        direccion = direcciones.ABAJO;
    }
    
    function derecha() public{
        direccion = direcciones.DERECHA;
    }
    
    function izquierda() public{
        direccion = direcciones.IZQUIERDA;
    }
    
    function fijarDirecciones(uint _k) public{
        direccion = direcciones(_k);
    }
    
    function Direcciones() public view returns(direcciones){
        return direccion;
    }
    
    
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/mas_variables.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract mas_variables{
    
    //Variables de tipo string (cadenas de texto)
    string mi_primer_string;
    string public saludo = "Hola, ¿cómo estais?";
    string public string_vacio = "";
    
    //Variables booleanas
    bool mi_primer_booleano;
    bool public  flag_true =true;
    bool public flag_false = false;
    
    //Variables de tipo bytes
    bytes32 mi_primer_bytes;
    bytes4 segundo_bytes;
    string public nombre = "Joan";
    bytes32 public hash = keccak256(abi.encodePacked(nombre));
    bytes4 public identificador;
    
    function ejemploBytes4() public{
        identificador = msg.sig;
    }
    
    //Variables address
    address mi_primera_direccion;
    address public direccion_local_1 = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
    address public direccion_local_2 = 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2;
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/unidades_tiempo.sol
================================================
// SPDX-License-Identifier: MIT
//Indicamos la version
pragma solidity >=0.4.4 <0.7.0;

contract timepo{
    
    //Unidades de tiempo
    uint public tiempo_actual = now;
    uint public un_minuto = 1 minutes;
    uint public dos_horas = 2 hours;
    uint public cincuenta_dias = 50 days;
    uint public una_semana = 1 weeks;
    
    //Operamos con las unidades de tiempo
    function MasSegundos() public view returns(uint){
        return now + 50 seconds;
    }
    
    function MasHoras() public view returns(uint){
        return now + 1 hours;
    }
    
    function MasDias() public view returns(uint){
        return now + 3 days;
    }
    
    function MasSemanas() public view returns(uint){
        return now + 1 weeks;
    }
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/variables_enteras.sol
================================================
// SPDX-License-Identifier: MIT
//Indicamos la version
pragma solidity >=0.4.4 <0.7.0;

contract enteros{
    
    //Variables enteras sin signo
    uint mi_primer_entero;
    uint mi_primer_entero_inicializado = 3;
    uint cota = 5000;
    
    //Variab enteras sin signo con un numero especifico de bits
    uint8 entero_8_bits;
    uint64 entero_64_bits = 7000;
    uint16 entero_16_bits;
    uint256 entero_256_bits;
    
    //Variables enteras con signo
    int mi_primer_entero_con_signo;
    int mi_numero = -32;
    int mi_numero_2 = 65;
    
    //Variables enteras con signo con un numero especfico de bits
    int72 entero_con_signo_72_bits;
    int240 entero_con_240_bits = 90000;
    int256 entero_con_256_bits;
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 4 - Estructuras de datos/Estructuras.sol
================================================
// SPDX-License-Identifier: MIT
//Especificamos la version
pragma solidity >=0.4.4 <0.7.0;

contract Estructuras{
    
    //Cliente de una pagina web de pago
    struct cliente{
        uint id;
        string name;
        string dni;
        string mail;
        uint phone_number;
        uint credit_number;
        uint secret_number;
    }
    
    //Declaramos una variable de tipo cliente
    cliente cliente_1 = cliente(1,"Joan", "12345678B", "joan@udemy.com", 12345678, 1234, 11);
    
    //Amazon (cualquier pagina de compra venta de productos)
    struct producto{
        string nombre;
        uint precio;
    }
    
    //Declaramos una variable de tipo producto
    producto movil = producto("samsung", 300);
     
    
    //Proyecto cooperativo de ONGs para ayudar en diversas causas
    struct ONG{
        address ong;
        string nombre;
    }
    //Declaramos una variable de tipo ONG
    //ONG caritas;
    ONG caritas = ONG(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, "Caritas");
    
    struct Causa{
        uint id;
        string nombre;
        uint precio_objetivo;
    }
    //Declaramos una variable de tipo Causa
    Causa medicamentos = Causa(1, "medicamentos", 1000);
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 4 - Estructuras de datos/arrays.sol
================================================
// SPDX-License-Identifier: MIT
//Indicamos la version
pragma solidity >=0.4.4 <0.7.0;

contract Arrays{
    
    //Array de enteros de longitud fija 5 
    uint[5] public array_enteros = [1,2,3];
    
    //Array de enteros de 32 bits de longitud fija con 7 posiciones
    uint32[7] array_enteros_32_bits;
    
    //Array de strings de longitud fija 15 
    string[15] arra_strings;
    
    //Array dinamico de enteros
    uint [] public array_dinamico_enteros;
    
    struct Persona{
        string nombre;
        uint edad;
    }
    
    //Array dinámico de tipo Persona
    Persona [] public array_dinamico_personas;
    
    function modificar_array() public{
       //array_dinamico_enteros.push(_numero);
       //array_dinamico_personas.push(Persona(_nombre, _edad));
       array_enteros[2]=56;
    }
    
    uint public test = array_enteros[2];
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 4 - Estructuras de datos/mappings.sol
================================================
// SPDX-License-Identifier: MIT
//Especificamos la version
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract Mappings{
    
    //Declaramos un mapping para elegir un numero
    mapping (address => uint) public elegirNumero;
    
    function ElegirNumero(uint _numero) public{
        elegirNumero[msg.sender] = _numero;
    }
    
    function consultarNumero() public view returns(uint){
        return elegirNumero[msg.sender];
    }
    
    //Declaramos un mapping que relaciona el nombre de una persona con su cantidad de dinero
    mapping (string => uint) cantidadDinero;
    
    function Dinero(string memory _nombre, uint _cantidad) public{
        cantidadDinero[_nombre] = _cantidad;
    }
    
    function consultarDinero(string memory _nombre) public view returns(uint){
        return cantidadDinero[_nombre];
    }
    
    //Ejemplo de mapping con un tipo de dato complejo
    struct Persona{
        string nombre;
        uint edad;
    }
    
    mapping(uint => Persona) personas;
    
    function dni_Persona(uint _numeroDni, string memory _nombre, uint _edad) public{
        personas[_numeroDni] = Persona(_nombre, _edad);
    }
    
    function VisualizarPersona(uint _dni) public view returns(Persona memory){
        return personas[_dni];
    }
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/causas_beneficas.sol
================================================
// SPDX-License-Identifier: MIT
//Especificamos la version
pragma solidity >=0.4.4 <0.7.0;

contract causasBeneficas{
    
    //Declaraciones necesarios
    struct Causa{
        uint Id;
        string name;
        uint precio_objectivo;
        uint cantidad_recaudada;
    }
    
    uint contador_causas=0;
    mapping (string => Causa) causas;
    
    //Permite dar de alta una nueva causa
    function nuevaCausa(string memory _nombre, uint _precio_objectivo) public payable{
        contador_causas = contador_causas++;
        causas[_nombre] = Causa(contador_causas, _nombre, _precio_objectivo, 0);
    }
    
    //Esta funcion nos devuelve true en caso de que podamos donar a una causa y false en caso contrario
    
    function objetivoCumplido(string memory _nombre, uint _donar) private view returns(bool){
        
        bool flag = false;
        Causa memory causa = causas[_nombre];
        
        if(causa.precio_objectivo >= (causa.cantidad_recaudada+_donar)){
            flag=true;
        }
        return flag;
        
    }
    
    
    //Esta funcion nos permite donar a una causa 
    function donar(string memory _nombre, uint _cantidad) public returns(bool){
        
        bool aceptar_donacion=true;
        
        if(objetivoCumplido(_nombre, _cantidad)){
            causas[_nombre].cantidad_recaudada = causas[_nombre].cantidad_recaudada + _cantidad;
        }else{
            aceptar_donacion = false;
        }
        return aceptar_donacion;
    }
    
    //Esta funcion nos dice si hemos llegado al precio objetivo 
    function comprobar_causa(string memory _nombre) public view returns(bool, uint){
        
        bool limite_alcanzado = false;
        Causa memory causa = causas[_nombre];
        
        if(causa.cantidad_recaudada>=causa.precio_objectivo){
            limite_alcanzado = true;
        }
        
        return (limite_alcanzado, causa.cantidad_recaudada);
        
    }
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/eventos.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract Eventos{
    
    //Declararmos los eventos a utilizar
    event nombre_evento1 (string _nombrePersona);
    event nombre_evento2 (string _nombrePersona, uint _edadPersona);
    event nombre_evento3(string, uint, address, bytes32);
    event abortarmision();
    
    function EmitirEvento1(string memory _nombrePersona) public{
        emit nombre_evento1(_nombrePersona);
    }
    
    function EmitirEvento2(string memory _nombrePersona, uint _edad) public{
        emit nombre_evento2(_nombrePersona, _edad);
    }
    
    function EmitirEvento3(string memory _nombrePersona, uint _edad) public{
        bytes32 hash_id = keccak256(abi.encodePacked(_nombrePersona, _edad, msg.sender)); 
        emit nombre_evento3(_nombrePersona, _edad, msg.sender, hash_id);
    }
    
    function AbortarMision() public {
        emit abortarmision();
    }
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/funciones.sol
================================================
// SPDX-License-Identifier: MIT
//Indicamos la version
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract funciones{
    
    //Añadir dentro de un array de direcciones, la direccion de la persona que llame a la funcion
    address[] public direcciones;
    
    function nuevaDireccion() public{
        direcciones.push(msg.sender);
    }
    
    //Computar el hash de los datos propocionados como parametro
    bytes32 public hash;
    
    function hash(string memory _datos) public{
        hash = keccak256(abi.encodePacked(_datos));
    }
    
    //Declaramos un tipo de dato complejo, que es comida
    struct comida{
        string nombre;
        string ingredientes;
    }
    
    //Vamos a crear un tipo de dato complejo comida
    comida public hamburguesa;
    
    function Hamburguesas(string memory _ingredientes) public{
        hamburguesa = comida("hamburguesa", _ingredientes);
    }
    
    //Declaramos un tipo de dato complejo, alumno
    struct alumno{
        string nombre;
        address direccion;
        uint edad;
    }
    
    bytes32 public hash_Id_alumno;
    
    //calculamos el hash del alumno
    function hashIdAlumno(string memory _nombre, address _direccion, uint _edad) private{
        hash_Id_alumno = keccak256(abi.encodePacked(_nombre, _direccion, _edad));
    }
    
    //Guardamos con la funcion publica dentro de una lista los alumnos
    alumno[] public lista;
    mapping (string => bytes32) alumnos;
    
    function nuevoAlumno(string memory _nombre, uint _edad) public{
        lista.push(alumno(_nombre, msg.sender, _edad));
        hashIdAlumno(_nombre, msg.sender, _edad);
        alumnos[_nombre] = hash_Id_alumno;
    }
    
    
    
}


================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/modificadores.sol
================================================
// SPDX-License-Identifier: MIT
//Indicamos la version
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract view_pure_payable{
    
    //Modificador de view
    string[] lista_alumnos;
    
    function nuevo_alumno(string memory _alumno) public{
        lista_alumnos.push(_alumno);
    }
    
    function ver_alumno(uint _posicion) public view returns(string memory){
        return lista_alumnos[_posicion];
    }
    
    uint x=10;
    function sumarAx(uint _a) public view returns(uint){
        return x+_a;
    }
    
    //Modificador de pure
    
    function exponenciacion(uint _a, uint _b) public pure returns(uint){
        return _a**_b;
    }
    
    //Modificador de payable
    
    mapping(address=>cartera) DineroCartera;
    
    struct cartera{
        string nombre_persona;
        address direccion_persona;
        uint dinero_persona;
    }
    
    function Pagar(string memory _nombrePersona, uint _cantidad) public payable{
        cartera memory mi_cartera;
        mi_cartera = cartera(_nombrePersona, msg.sender, _cantidad);
        DineroCartera[msg.sender] = mi_cartera;
    }
    
    function verSaldo() public view returns(cartera){
        return DineroCartera[msg.sender];
    }
    
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/returns.sol
================================================
// SPDX-License-Identifier: MIT
//Especificamos la version
pragma solidity >=0.4.4 <0.7.0;

contract ValoresDeRetorno{
    
    //Funcion que nos devuelva un saludo
    function saludos() public returns(string){
        return "saludos";
    }
    
    //Esta funcion calcula el resultado de una multiplicacion de dos numeros enteros
    function Multiplicacion(uint _a, uint _b) public returns(uint){
        return _a*_b;
    }
    
    //Esta funcion devuelve true si el numero es par y false en caso contrario
    function par_impar(uint _a) public returns(bool){
        
        bool flag;
        
        if(_a%2==0){
            flag=true;
        }else{
            flag=false;
        }
        
        return flag;
    }
    
    //Realizamos una funcion que nos devuelve el cociente y el residuo de una division
    // ademas de una variable booleana que es true si el residuo es 0 y false en caso contrario
    function division(uint _a, uint _b) public returns(uint, uint, bool){
        uint q = _a/_b;
        uint r = _a % _b;
        bool multiplo=false;
        
        if(r==0){
            multiplo=true;
        }
        
        return (q,r,multiplo);
    }
    
    //Practica para el manejo de los valores devueltos
    
    function numeros() public returns(uint, uint, uint, uint, uint, uint){
        return (1,2,3,4,5,6);
    }
    
    //Asignacion multiple
    
    function todos_los_valores() public{
        
        //Declaramos las variables donde se guardan los valores de retorno de la funcion numeros()
        uint a;
        uint b;
        uint c;
        uint d;
        uint e;
        uint f;
        //Realizar la asignacion multiple
        (a,b,c,d,e,f)=numeros();
    }
    
    function ultimo_valor() public{
        
        (,,,,,uint ultimo)=numeros();
    }
    
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 6 - Bucles y condicionales/bucle_for.sol
================================================
// SPDX-License-Identifier: MIT
//Especificar la version
pragma solidity >=0.4.4 <0.7.0;

contract bucle_for{
    
    //Suma de los 100 primeros numeros a partir del numero introducido
    
    function suma(uint _numero) public pure returns(uint){
        
        uint Suma = 0;
        
        for(uint i =_numero; i<(100+_numero); i++){
            Suma = Suma +i;
        }
        
        return Suma;
    }
    
    //Esto es un array dinamico de direcciones
    address [] direcciones;
    
    //Añade una direccion al array
    function asociar() public{
        direcciones.push(msg.sender);
    }
    
    //Comprobar si la direccion esta en el array de direcciones
    function comprobarAsociacion() public view returns(bool, address){
        
        for(uint i=0; i< direcciones.length; i++){
            if(msg.sender==direcciones[i]){
                return (true, direcciones[i]);
            }
        }
    }
    
    //Doble for: Suma los 10 primeros factoriales
    //n! = n*(n-1)*(n-2)*...*2*1
    
    function sumaFactorial() public pure returns(uint){
        
        uint suma=0;
        for(uint i =1; i<=10; i++){
            
            uint factorial = 1;
            
            for(uint j=2; j<=i; j++){
                factorial = factorial*j;
            }
            
            suma = suma + factorial;
        }
        return suma;
    }
}




================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 6 - Bucles y condicionales/bucle_while.sol
================================================
// SPDX-License-Identifier: MIT
//Especificamos la version
pragma solidity >=0.4.4 <0.7.0;

contract bucle_while{
    
    //Suma de los numeros impares menores o iguales 100
    
    function suma_impares() public pure returns(uint){
        
        uint suma =0;
        uint contador=1;
        
        while(contador<100){
            
            if(contador%2!=0){
                suma = suma + contador;
            }
            
            contador++;
        }
        
        return suma;
    }
    
    //Esperar 5 segundos
    
    uint tiempo;
    
    function fijarTiempo() public{
        tiempo = now;
    }
    
    function espera() public view returns(bool){
        
        while(now < tiempo+ 5 seconds){
            return false;
        }
        
        return true;
    }
    
    //Siguiente numero primo
    //Numero primo es aquel que es divisible entre 1 y el mismo
    
    function siguientePrimo(uint _p) public pure returns(uint){
        
        uint contador =_p+1;
        
        while(true){
            
            //Comprobamos si contador es primo
            uint aux=2;
            bool primo =true;
            
            while(aux<contador){
                if(contador%aux==0){
                    primo =false;
                    break;
                }
                aux++;
            }
            
            if(primo==true){
                break;
            }
            
            contador++;
            
        }
        return contador;
    }
    
}




================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 6 - Bucles y condicionales/sentencia_if.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;

contract sentencia_if{
    
    //Numero ganador
    function probarSuerte(uint _numero) public pure returns(bool){
        
        bool ganador;
        if(_numero == 100){
            ganador=true;
        }else{
            ganador = false;
        }
        
        return ganador;
        
        /*
        bool ganador = false;
        if(_numero==100){
            ganador =true;
        }
        return ganador;
        */
    }
    
    //Calculamos el valor absoluto de un numero
    
    function valorAbsoluto(int _k) public pure returns(uint){
        
        uint valor_absoluto_numero;
        if(_k<0){
            valor_absoluto_numero = uint(-_k);
        }else{
            valor_absoluto_numero = uint(_k);
        }
        
        return valor_absoluto_numero;
    }
    
    //Devolver true si el numero introducido es par y tiene tres cifras
    
    function parTresCifras(uint _numero) public pure returns(bool){
        bool flag;
        
        if((_numero%2==0)&&(_numero>=100)&&(_numero<999)){
            flag = true;
        }else{
            flag=false;
        }
        
        return flag;
    }
    
    //Votacion
    //Solo hay tres candidatos: Joan, Gabriel y Maria
    
    function votar(string memory _candidato) public pure returns(string memory){
        
        string memory mensaje;
        
        if(keccak256(abi.encodePacked(_candidato))==keccak256(abi.encodePacked("Joan"))){
            mensaje = "Has votado correctamente a Joan";
        }else{
            if(keccak256(abi.encodePacked(_candidato))==keccak256(abi.encodePacked("Gabriel"))){
                mensaje = "Has votado correctamente a Gabriel";
            }else{
                if(keccak256(abi.encodePacked(_candidato))==keccak256(abi.encodePacked("Maria"))){
                    mensaje = "Has votado correctamente a Maria";
                }else{
                    mensaje = "Has votado a un candidato que no está en la lista";
                }
            }
        }
        
        return mensaje;
    }
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 7 - Interactuando con otros Smart Contracts/Banco.sol
================================================
// SPDX-License-Identifier: MIT
//Indicamos la version
pragma solidity >=0.4.4 <0.7.0;

contract Banco{
    
    //Definimos un tipo de dato complejo cliente
    struct cliente{
        string _nombre;
        address direccion;
        uint dinero;
    }
    
    //mapping que nos relacionar el nombre del cliente con el tipo de dato cliente
    mapping (string => cliente) clientes;
    
    //Funcion que nos permita dar de alta un nuevo cliente
    
    function nuevoCliente(string memory _nombre) public {
        clientes[_nombre] = cliente(_nombre, msg.sender, 0);
    }
}

contract Banco2{
    
}

contract Banco3{
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 7 - Interactuando con otros Smart Contracts/Cliente.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
//import "./Banco.sol";
import {Banco, Banco2} from "./Banco.sol";


contract Cliente is Banco{
    
    function AltaCliente(string memory _nombre) public{
        nuevoCliente(_nombre);
    }
    
    function IngresarDinero(string memory _nombre, uint _cantidad) public{
        clientes[_nombre].dinero = clientes[_nombre].dinero + _cantidad;
    }
    
    function RetirarDinero(string memory _nombre, uint _cantidad) public returns(bool){
        bool flag = true;
        
        if(int(clientes[_nombre].dinero)-int(_cantidad) >= 0){
            clientes[_nombre].dinero = clientes[_nombre].dinero - _cantidad;
        }else{
            flag = false;
        }
        
        return flag;
    }
    
    function ConsultarDinero(string memory _nombre) public view returns(uint){
        return clientes[_nombre].dinero;
    }
}




================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 7 - Interactuando con otros Smart Contracts/herencia.sol
================================================
// SPDX-License-Identifier: MIT
//Indicamos la version
pragma solidity >=0.4.4 <0.7.0;

contract Banco{
    
    //Definimos un tipo de dato complejo cliente
    struct cliente{
        string _nombre;
        address direccion;
        uint dinero;
    }
    
    //mapping que nos relacionar el nombre del cliente con el tipo de dato cliente
    mapping (string => cliente) clientes;
    
    //Funcion que nos permita dar de alta un nuevo cliente
    
    function nuevoCliente(string memory _nombre) public {
        clientes[_nombre] = cliente(_nombre, msg.sender, 0);
    }
}

contract Cliente is Banco{
    
    function AltaCliente(string memory _nombre) public{
        nuevoCliente(_nombre);
    }
    
    function IngresarDinero(string memory _nombre, uint _cantidad) public{
        clientes[_nombre].dinero = clientes[_nombre].dinero + _cantidad;
    }
    
    function RetirarDinero(string memory _nombre, uint _cantidad) public returns(bool){
        bool flag = true;
        
        if(int(clientes[_nombre].dinero)-int(_cantidad) >= 0){
            clientes[_nombre].dinero = clientes[_nombre].dinero - _cantidad;
        }else{
            flag = false;
        }
        
        return flag;
    }
    
    function ConsultarDinero(string memory _nombre) public view returns(uint){
        return clientes[_nombre].dinero;
    }
}




================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 7 - Interactuando con otros Smart Contracts/librerias.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;

library Operaciones{
    
    function division(uint _i, uint _j) public pure returns(uint){
        require(_j>0, "No podemos dividir por 0");
        return _i/_j;
    }
    
    function multiplicacion(uint _i, uint _j) public pure returns(uint){
        
        if((_i==0)||(_j==0)){
            return 0;
        }else{
            return _i*_j;
        }
        
    }
}

contract calculos{
    
    using Operaciones for uint;
    
    function calculo(uint _a, uint _b) public pure returns(uint, uint){
        uint q = _a.division(_b);
        uint m = _a.multiplicacion(_b);
        return (q,m);
    }
    
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 8 - Funciones avanzadas/internal_external.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 0.7.0;

contract Comida{
    
    struct plato{
        string nombre;
        string ingredientes;
        uint tiempo;
    }
    //Declarar un array dinamico de platos
    plato [] platos;
    //Relacionamos con un mapping el nombre del plato con sus ingredientes
    mapping(string => string) ingredientes;
    
    //Funcion que nos permite dar de alta un nuevo plato 
    function NuevoPlato(string memory _nombre, string memory _ingredientes, uint _tiempo) internal{
        platos.push(plato(_nombre, _ingredientes, _tiempo));
        ingredientes[_nombre] = _ingredientes;
    }
    
    function Ingredientes(string memory _nombre) internal view returns(string memory){
        return ingredientes[_nombre];
    }
    
}

contract Sandwitch is Comida{
    
    function sandwitch(string memory _ingredientes, uint _tiempo) external{
        NuevoPlato("Sandwitch", _ingredientes, _tiempo);
    }
    
    function verIngredientes() external view returns (string memory){
        return Ingredientes("Sandwitch");
    }
    
    
}




================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 8 - Funciones avanzadas/modifier.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;

contract Modifer{
    
    
    //Ejemplo de solo propietario del contrato puede ejecutar una funcion 
    
    address public owner;
    
    constructor() public{
        owner = msg.sender;
    }
    
    modifier soloPropietario(){
        require(msg.sender==owner, "No tienes permisos para ejecutar la funcion");
        _;
    }
    
    function ejemplo1() public soloPropietario(){
        //Codigo de la funcion parar el propietario del contrato
    }
    
    struct cliente{
        address direccion;
        string nombre;
    }
    
    mapping(string => address) clientes;
    
    function altaCliente(string memory _nombre) public {
        clientes[_nombre] = msg.sender;
    }
    
    modifier soloClientes(string memory _nombre){
        require(clientes[_nombre] == msg.sender);
        _;
    }
    
    function ejemplo2(string memory _nombre) public soloClientes(_nombre){
       //Logica de la funcion para los clientes 
    }
    
    //Ejemplo de conduccion
    
    modifier MayorEdad(uint _edadMinima, uint _edadUsuario){
        require(_edadUsuario>=_edadMinima);
        _;
    }
    
    function conducir(uint _edad) public MayorEdad(18, _edad){
        //Codigo a ejecutar para los conductores mayores de edad 
    }
    
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 8 - Funciones avanzadas/require.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;

contract Rquire{
    
    //Funcion que verfique la contraseña
    function password(string memory _pas) public pure returns(string memory){
        require(keccak256(abi.encodePacked(_pas))==keccak256(abi.encodePacked("12345")), "Contraseña incorrecta");
        return "contraseña correcta";
    }
    
    //Funcion para pagar
    uint tiempo=0;
    uint public cartera=0;
    
    function pagar(uint _cantidad) public returns(uint){
        require(now > tiempo + 5 seconds, "Aun no puedes pagar");
        tiempo = now;
        cartera = cartera + _cantidad;
        return cartera;
    }
    
    //funcion con una lista
    
    string [] nombres;
    
    function nuevoNombre(string memory _nombre) public{
        for(uint i =0; i<nombres.length; i++){
            require(keccak256(abi.encodePacked(_nombre))!=keccak256(abi.encodePacked(nombres[i])), "ya está en la lista");
        }
        
        nombres.push(_nombre);
    }
    
}

================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 9 - SafeMath/SafeMath.sol
================================================
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// Implementacion de la libreria SafeMath para realizar las operaciones de manera segura
// Fuente: "https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be"

library SafeMath{
    // Restas
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }
    
    // Sumas
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
    
    // Multiplicacion
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
}


================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 9 - SafeMath/SafeMath_comentada.sol
================================================
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// Implementacion de la libreria SafeMath para realizar las operaciones de manera segura
// Fuente: "https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be"

/*

uint8 numero = 255;

Tenemos 2^8 posibles numeros --> [0, 255];

numero++; ---> OVERFLOW

*/


library SafeMath{
    
    // Restas
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }
    
    // Sumas
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
    
    // Multiplicacion
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
}





================================================
FILE: BLOQUE 1 - Conceptos básicos de Solidity/Tema 9 - SafeMath/ejemplo_uso.sol
================================================
// SPDX-License-Identifier: MIT
//Indicar la version
pragma solidity >=0.4.4 <0.7.0;
import "./SafeMath.sol";


contract calculosSeguros{
    
    //Debemos declarar para que tipo de datos usaremos la libreria
    using SafeMath for uint;
    
    //Funcion suma segura
    
    function suma(uint _a, uint _b) public pure returns(uint){
        return _a.add(_b);
    }
    
    //Funcion resta
    function resta(uint _a, uint _b) public pure returns(uint){
        return _a.sub(_b);
    }
    
    //funcion multiplicacion
    function multiplicacion(uint _a, uint _b) public pure returns(uint){
        return _a.mul(_b);
    }
    
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/Creación y uso de un Token ERC-20/ERC20.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 < 0.7.0;
pragma experimental ABIEncoderV2;
import "./SafeMath.sol";



//Juan Gabriel ---> 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
//Juan Amengual ---> 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
//María Santos ---> 0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db

//Interface de nuestro token ERC20
interface IERC20{
    //Devuelve la cantidad de tokens en existencia
    function totalSupply() external view returns (uint256);

    //Devuelve la cantidad de rokens para una dirección indicada por parámetro
    function balanceOf(address account) external view returns (uint256);

    //Devuelve el número de token que el spender podrá gastar en nombre del propietario (owner)
    function allowance(address owner, address spender) external view returns (uint256);

    //Devuelve un valor booleano resultado de la operación indicada
    function transfer(address recipient, uint256 amount) external returns (bool);

    //Devuelve un valor booleano con el resultado de la operación de gasto
    function approve(address spender, uint256 amount) external returns (bool);

    //Devuelve un valor booleano con el resultado de la operación de paso de una cantidad de tokens usando el método allowance()
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);



    //Evento que se debe emitir cuando una cantidad de tokens pase de un origen a un destino
    event Transfer(address indexed from, address indexed to, uint256 value);

    //Evento que se debe emitir cuando se establece una asignación con el mmétodo allowance()
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

//Implementación de las funciones del token ERC20
contract ERC20Basic is IERC20{

    string public constant name = "ERC20BlockchainAZ";
    string public constant symbol = "ERC";
    uint8 public constant decimals = 18;

    event Transfer(address indexed from, address indexed to, uint256 tokens);
    event Approval(address indexed owner, address indexed spender, uint256 tokens);


    using SafeMath for uint256;

    mapping (address => uint) balances;
    mapping (address => mapping (address => uint)) allowed;
    uint256 totalSupply_;

    constructor (uint256 initialSupply) public{
        totalSupply_ = initialSupply;
        balances[msg.sender] = totalSupply_;
    }


    function totalSupply() public override view returns (uint256){
        return totalSupply_;
    }

    function increaseTotalSupply(uint newTokensAmount) public {
        totalSupply_ += newTokensAmount;
        balances[msg.sender] += newTokensAmount;
    }

    function balanceOf(address tokenOwner) public override view returns (uint256){
        return balances[tokenOwner];
    }

    function allowance(address owner, address delegate) public override view returns (uint256){
        return allowed[owner][delegate];
    }

    function transfer(address recipient, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        balances[recipient] = balances[recipient].add(numTokens);
        emit Transfer(msg.sender, recipient, numTokens);
        return true;
    }

    function approve(address delegate, uint256 numTokens) public override returns (bool){
        allowed[msg.sender][delegate] = numTokens;
        emit Approval(msg.sender, delegate, numTokens);
        return true;
    }

    function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[owner]);
        require(numTokens <= allowed[owner][msg.sender]);

        balances[owner] = balances[owner].sub(numTokens);
        allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(owner, buyer, numTokens);
        return true;
    }
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/Creación y uso de un Token ERC-20/SafeMath.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// Implementacion de la libreria SafeMath para realizar las operaciones de manera segura
// Fuente: "https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be"

library SafeMath{
    // Restas
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }
    
    // Sumas
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
    
    // Multiplicacion
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
}


================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/DISNEY/ERC20.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;
import "./SafeMath.sol";


interface IERC20{
    function totalSupply() external view returns (uint256);
    function balanceOf (address account) external view returns (uint256);
    function allowance(address owner,address spender) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function transferencia_disney(address sender, address recipient, uint256 amount) external returns (bool);
    function approve (address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval (address indexed owner, address indexed spender, uint256 value);
}

contract ERC20Basic is IERC20 {
    string public constant name = "ERC20Basic";
    string public constant symbol = "JBJ-TOKEN";
    uint8 public constant decimals = 2;
    
    event Transfer(address indexed from, address indexed to, uint256 tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
    
    mapping (address => uint) balances;
    mapping(address => mapping (address => uint)) allowed;
    uint256 totalSupply_;
    
    using SafeMath for uint256;
    
    constructor (uint256 total) public{
        totalSupply_ = total;
        balances[msg.sender] = totalSupply_;
    }
    
    function totalSupply() public override view returns (uint256){
        return totalSupply_;
    }
    
    function increaseTotalSuply(uint newTokens) public{
        totalSupply_ += newTokens;
        balances[msg.sender] += newTokens;
    }
    
    function balanceOf (address tokenOwner) public override view returns (uint256){
        return balances[tokenOwner];
    }
    
    function transfer(address receiver, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(msg.sender,receiver,numTokens);
        return true;
    } 
    
    function transferencia_disney(address sender, address receiver, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[sender]);
        balances[sender] = balances[sender].sub(numTokens);
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(sender,receiver,numTokens);
        return true;
    } 
    
    function approve (address delegate, uint256 numTokens) public override returns (bool) {
        allowed[msg.sender][delegate] = numTokens;
        emit Approval(msg.sender, delegate, numTokens);
        return true;
    }
    
    function allowance (address owner, address delegate) public override view returns (uint){
        return allowed[owner][delegate];
    }
    
    function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool){
        require (numTokens <= balances[owner]);
        require (numTokens <= allowed[owner][msg.sender]);
        
        balances[owner] = balances[owner].sub(numTokens);
        allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(owner,buyer,numTokens);
        return true;
    }
    
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/DISNEY/SafeMath.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// Implementacion de la libreria SafeMath para realizar las operaciones de manera segura
// Fuente: "https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be"

library SafeMath{
    // Restas
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }
    
    // Sumas
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
    
    // Multiplicacion
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
}


================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/DISNEY/disney.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;
import "./ERC20.sol";

contract Disney{
    
    // --------------------------------- DECLARACIONES INICIALES ---------------------------------
    
    // Instancia del contato token
    ERC20Basic private token;
    
    // Direccion de Disney (owner)
    address payable public owner;
    
    // Constructor 
    constructor () public {
        token = new ERC20Basic(10000);
        owner = msg.sender;
    }
    
    // Estructura de datos para almacenar a los clientes de Disney
    struct cliente {
        uint tokens_comprados;
        string [] atracciones_disfrutadas;
    }
    
    // Mapping para el registro de clientes
    mapping (address => cliente) public Clientes;
    
    
    // --------------------------------- GESTION DE TOKENS ---------------------------------
    
    // Funcion para establecer el precio de un Token 
    function PrecioTokens(uint _numTokens) internal pure returns (uint) {
        // Conversion de Tokens a Ethers: 1 Token -> 1 ether
        return _numTokens*(1 ether);
    }
    
    // Funcion para comprar Tokens en disney y disfrutar de las atracciones 
    function CompraTokens(uint _numTokens) public payable {
        // Establecer el precio de los Tokens
        uint coste = PrecioTokens(_numTokens);
        // Se evalua el dinero que el cliente paga por los Tokens
        require (msg.value >= coste, "Compra menos Tokens o paga con mas ethers.");
        // Diferencia de lo que el cliente paga
        uint returnValue = msg.value - coste;
        // Disney retorna la cantidad de ethers al cliente
        msg.sender.transfer(returnValue);
        // Obtencion del numero de tokens disponibles
        uint Balance = balanceOf();
        require(_numTokens <= Balance, "Compra un numero menor de Tokens");
        // Se transfiere el numero de tokens al cliente
        token.transfer(msg.sender, _numTokens);
        // Registro de tokens comprados
        Clientes[msg.sender].tokens_comprados += _numTokens;
    }
    
    // Balance de tokens del contrato disney
    function balanceOf() public view returns (uint) {
        return token.balanceOf(address(this));
    }
    
    // Visualizar el numero de tokens restantes de un Cliente 
    function MisTokens() public view returns (uint){
        return token.balanceOf(msg.sender);
    }
    
    // Funcion para generar mas tokens 
    function GeneraTokens(uint _numTokens) public Unicamente(msg.sender) {
        token.increaseTotalSuply(_numTokens);
    }
    
    // Modificador para controlar las funciones ejecutables por disney 
    modifier Unicamente(address _direccion) {
        require(_direccion == owner, "No tienes permisos para ejecutar esta funcion.");
        _;
    }
    
    // --------------------------------- GESTION DE DISNEY ---------------------------------
    
    // Eventos 
    event disfruta_atraccion(string, uint, address);
    event nueva_atraccion(string, uint);
    event baja_atraccion(string);
    event nueva_comida(string, uint, bool);
    event baja_comida(string);
    event disfruta_comida(string, uint, address);
    
    // Estructura de la atraccion 
    struct atraccion {
        string nombre_atraccion;
        uint precio_atraccion;
        bool estado_atraccion;
    }
    
    // Estructura de la comida 
    struct comida {
        string nombre_comida;
        uint precio_comida;
        bool estado_comida;
    }
    
    // Mapping para relacion un nombre de una atraccion con una estructura de datos de la atraccion
    mapping (string => atraccion) public MappingAtracciones;
    
    // Mapping para relacion un nombre de una comida con una estructura de datos de la comida
    mapping (string => comida) public MappingComida;
    
    // Array para almacenar el nombre de las atracciones 
    string [] Atracciones;
    
    // Array para almacenar el nombre de las atracciones 
    string [] Comidas;
    
    // Mapping para relacionar una identidad (cliente) con su historial de atracciones en DISNEY
    mapping (address => string []) HistorialAtracciones;
    
    // Mapping para relacionar una identidad (cliente) con su historial de comidas en DISNEY
    mapping (address => string []) HistorialComidas;
    
    // Star Wars -> 2 Tokens
    // Toy Story -> 5 Tokens 
    // Piratas del Caribe -> 8 Tokens 
    
    // Crear nuevas atracciones para DISNEY (SOLO es ejecutable por Disney)
    function NuevaAtraccion(string memory _nombreAtraccion, uint _precio) public Unicamente (msg.sender) {
        // Creacion de una atraccion en Disney 
        MappingAtracciones[_nombreAtraccion] = atraccion(_nombreAtraccion,_precio, true);
        // Almacenamiento en un array el nombre de la atraccion 
        Atracciones.push(_nombreAtraccion);
        // Emision del evento para la nueva atraccion 
        emit nueva_atraccion(_nombreAtraccion, _precio);
    }
    
    // Crear nuevos menus para la comida en DISNEY (SOLO es ejecutable por Disney)
    function NuevaComida(string memory _nombreComida, uint _precio) public Unicamente (msg.sender) {
        // Creacion de una comida en Disney
        MappingComida[_nombreComida] = comida(_nombreComida, _precio, true);
        // Almacenar en un array las comidas que puede realizar una persona
        Comidas.push(_nombreComida);
        // Emision del evento para la nueva comida en Disney 
        emit nueva_comida(_nombreComida, _precio, true);
    }
    
    // Dar de baja a las atracciones en Disney 
    function BajaAtraccion (string memory _nombreAtraccion) public Unicamente(msg.sender){
        // El estado de la atraccion pasa a FALSE => No esta en uso 
        MappingAtracciones[_nombreAtraccion].estado_atraccion = false;
        // Emision del evento para la baja de la atraccion 
        emit baja_atraccion(_nombreAtraccion);
     }
     
    // Dar de baja una comida de Disney 
    function BajaComida (string memory _nombreComida) public Unicamente(msg.sender){
        // El estado de la comida pasa a FALSE => No se puede comer
        MappingComida[_nombreComida].estado_comida = false;
        // Emision del evento para la baja de la comida 
        emit baja_comida(_nombreComida);
     }
    
    // Visualizar las atracciones de Disney 
    function AtraccionesDisponibles() public view returns (string [] memory){
        return Atracciones;
    }
    
    // Visualizar las comidas de Disney 
    function ComidasDisponibles() public view returns (string [] memory){
        return Comidas;
    }
    
    // Funcion para subirse a una atraccion de disney y pagar en tokens 
    function SubirseAtraccion (string memory _nombreAtraccion) public {
        // Precio de la atraccion (en tokens)
        uint tokens_atraccion = MappingAtracciones[_nombreAtraccion].precio_atraccion;
        // Verifica el estado de la atraccion (si esta disponible para su uso)
        require (MappingAtracciones[_nombreAtraccion].estado_atraccion == true, 
                    "La atraccion no esta disponible en estos momentos.");
        // Verifica el numero de tokens que tiene el cliente para subirse a la atraccion 
        require(tokens_atraccion <= MisTokens(), 
                "Necesitas mas Tokens para subirte a esta atraccion.");
        
        /* El cliente paga la atraccion en Tokens:
        - Ha sido necesario crear una funcion en ERC20.sol con el nombre de: 'transferencia_disney'
        debido a que en caso de usar el Transfer o TransferFrom las direcciones que se escogian 
        para realizar la transccion eran equivocadas. Ya que el msg.sender que recibia el metodo Transfer o
        TransferFrom era la direccion del contrato.
        */
        token.transferencia_disney(msg.sender, address(this),tokens_atraccion);
        // Almacenamiento en el historial de atracciones del cliente 
        HistorialAtracciones[msg.sender].push(_nombreAtraccion);
        // Emision del evento para disfrutar de la atraccion 
        emit disfruta_atraccion(_nombreAtraccion, tokens_atraccion, msg.sender);
    }
    
    // Funcion para comprar comida con tokens
    function ComprarComida (string memory _nombreComida) public {
        // Precio de la comida (en tokens)
        uint tokens_comida = MappingComida[_nombreComida].precio_comida;
        // Verifica el estado de la comida (si esta disponible)
        require (MappingComida[_nombreComida].estado_comida == true, 
                    "La comida no esta disponible en estos momentos.");
        // Verifica el numero de tokens que tiene el cliente para comer esa comida
        require(tokens_comida <= MisTokens(), 
                "Necesitas mas Tokens para comer esta comida.");
        
        /* El cliente paga la atraccion en Tokens:
        - Ha sido necesario crear una funcion en ERC20.sol con el nombre de: 'transferencia_disney'
        debido a que en caso de usar el Transfer o TransferFrom las direcciones que se escogian 
        para realizar la transccion eran equivocadas. Ya que el msg.sender que recibia el metodo Transfer o
        TransferFrom era la direccion del contrato.
        */
        token.transferencia_disney(msg.sender, address(this),tokens_comida);
        // Almacenamiento en el historial de comidas del cliente 
        HistorialComidas[msg.sender].push(_nombreComida);
        // Emision del evento para disfrutar de la comida 
        emit disfruta_comida(_nombreComida, tokens_comida, msg.sender);
    }
    
    // Visualiza el historial completo de atracciones disfrutadas por un cliente 
    function Historial() public view returns (string [] memory) {
        return HistorialAtracciones[msg.sender];
    }
    
    // Visualiza el historial completo de comidas disfrutadas por un cliente 
    function HistorialComida() public view returns (string [] memory) {
        return HistorialComidas[msg.sender];
    }
    
    // Funcion para que un cliente de Disney pueda devolver Tokens 
    function DevolverTokens (uint _numTokens) public payable {
        // El numero de tokens a devolver es positivo
        require (_numTokens > 0, "Necesitas devolver una cantidad positiva de tokens.");
        // El usuario debe tener el numero de tokens que desea devolver 
        require (_numTokens <= MisTokens(), "No tienes los tokens que deseas devolver.");
        // El cliente devuelve los tokens 
         token.transferencia_disney(msg.sender, address(this),_numTokens);
         // Devolucion de los ethers al cliente 
         msg.sender.transfer(PrecioTokens(_numTokens));
    }
    
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/Evaluaciones universitarias con un Smart Contract/notas.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 < 0.7.0;
pragma experimental ABIEncoderV2;

// -----------------------------------
//  ALUMNO   |    ID    |      NOTA
// -----------------------------------
//  Marcos |    77755N    |      5
//  Joan   |    12345X    |      9
//  Maria  |    02468T    |      2
//  Marta  |    13579U    |      3
//  Alba   |    98765Z    |      5

contract notas {
    
    // Direccion del profesor
    address public profesor;
    
    // Constructor 
    constructor () public {
        profesor = msg.sender;
    }
    
    // Mapping para relacionar el hash de la identidad del alumno con su nota del examen
    mapping (bytes32 => uint) Notas;
    
    // Array de los alumnos de pidan revisiones de examen
    string [] revisiones;
    
    // Eventos 
    event alumno_evaluado(bytes32);
    event evento_revision(string);
    
    // Funcion para evaluar a alumnos
    function Evaluar(string memory _idAlumno, uint _nota) public UnicamenteProfesor(msg.sender){
        // Hash de la identificacion del alumno 
        bytes32 hash_idAlumno = keccak256(abi.encodePacked(_idAlumno));
        // Relacion entre el hash de la identificacion del alumno y su nota
        Notas[hash_idAlumno] = _nota;
        // Emision del evento
        emit alumno_evaluado(hash_idAlumno);
    }
    
    // Control de las funciones ejecutables por el profesor
    modifier UnicamenteProfesor(address _direccion){
        // Requiere que la direccion introducido por parametro sea igual al owner del contrato
        require(_direccion == profesor, "No tienes permisos para ejecutar esta funcion.");
        _;
    }
    
    // Funcion para ver las notas de un alumno 
    function VerNotas(string memory _idAlumno) public view returns(uint) {
        // Hash de la identificacion del alumno 
        bytes32 hash_idAlumno = keccak256(abi.encodePacked(_idAlumno));
        // Nota asociada al hash del alumno
        uint nota_alumno = Notas[hash_idAlumno];
        // Visualizar la nota 
        return nota_alumno;
    } 
    
    // Funcion para pedir una revision del examen
    function Revision(string memory _idAlumno) public {
        // Almacenamiento de la identidad del alumno en un array
        revisiones.push(_idAlumno);
        // Emision del evento 
        emit evento_revision(_idAlumno);
    }
    
    // Funcion para ver los alumnos que han solicitado revision de examen
    function VerRevisiones() public view UnicamenteProfesor(msg.sender) returns (string [] memory){
        // Devolver las identidades de los alumnos
        return revisiones;
    }
    
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/LOTERIA/ERC20.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;
import "./SafeMath.sol";


interface IERC20{
    function totalSupply() external view returns (uint256);
    function balanceOf (address account) external view returns (uint256);
    function allowance(address owner,address spender) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function transferencia_loteria(address sender, address recipient, uint256 amount) external returns (bool);
    function approve (address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval (address indexed owner, address indexed spender, uint256 value);
}

contract ERC20Basic is IERC20 {
    string public constant name = "ERC20Basic";
    string public constant symbol = "JBJ-TOKEN";
    uint8 public constant decimals = 2;
    
    event Transfer(address indexed from, address indexed to, uint256 tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
    
    mapping (address => uint) balances;
    mapping(address => mapping (address => uint)) allowed;
    uint256 totalSupply_;
    
    using SafeMath for uint256;
    
    constructor (uint256 total) public{
        totalSupply_ = total;
        balances[msg.sender] = totalSupply_;
    }
    
    function totalSupply() public override view returns (uint256){
        return totalSupply_;
    }
    
    function increaseTotalSuply(uint newTokens) public{
        totalSupply_ += newTokens;
        balances[msg.sender] += newTokens;
    }
    
    function balanceOf (address tokenOwner) public override view returns (uint256){
        return balances[tokenOwner];
    }
    
    function transfer(address receiver, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(msg.sender,receiver,numTokens);
        return true;
    } 
    
    function transferencia_loteria(address sender, address receiver, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[sender]);
        balances[sender] = balances[sender].sub(numTokens);
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(sender,receiver,numTokens);
        return true;
    } 
    
    function approve (address delegate, uint256 numTokens) public override returns (bool) {
        allowed[msg.sender][delegate] = numTokens;
        emit Approval(msg.sender, delegate, numTokens);
        return true;
    }
    
    function allowance (address owner, address delegate) public override view returns (uint){
        return allowed[owner][delegate];
    }
    
    function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool){
        require (numTokens <= balances[owner]);
        require (numTokens <= allowed[owner][msg.sender]);
        
        balances[owner] = balances[owner].sub(numTokens);
        allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(owner,buyer,numTokens);
        return true;
    }
    
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/LOTERIA/SafeMath.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// Implementacion de la libreria SafeMath para realizar las operaciones de manera segura
// Fuente: "https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be"

library SafeMath{
    // Restas
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }
    
    // Sumas
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
    
    // Multiplicacion
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/LOTERIA/loteria.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;
import "./ERC20.sol";


contract loteria {
    
    // Instancia del contrato Token 
    ERC20Basic private token;
    
    // Direcciones 
    address public owner;
    address public contrato;
    
    // Numero de tokens a crear 
    uint tokens_creados = 10000;
    
    // Evento de compra de tokens 
    event ComprandoTokens (uint, address);
    
    constructor () public {
        token = new ERC20Basic(tokens_creados);
        owner = msg.sender;
        contrato = address(this);
    }
    
    // ----------------------------------------  TOKEN ---------------------------------------- 
    
    // Establecer el precio de lo tokens en ethers 
    function PrecioTokens(uint _numTokens) internal pure returns (uint){
        return _numTokens*(1 ether);
    }
    
    // Generar mas Tokens por la Loteria 
    function GeneraTokens(uint _numTokens) public Unicamente(msg.sender){
        token.increaseTotalSuply(_numTokens);
    }
    
    // Modificador para hacer funciones solamente accesibles por el owner del contrato
    modifier Unicamente(address _direccion) {
        require (_direccion == owner, "No tienes permisos para ejecutar esta funcion.");
        _;
    }
    
    // Comprar Tokens para comprar boletos/tickets para la loteria 
    function CompraTokens(uint _numTokens) public payable {
        // Calcular el coste de los tokens 
        uint coste = PrecioTokens(_numTokens);
        // Se requiere que el valor de ethers pagados sea equivalente al coste 
        require (msg.value >= coste, "Compra menos Tokens o paga con mas Ethers.");
        // Diferencia a pagar 
        uint returnValue = msg.value - coste;
        // Tranferencia de la diferencia 
        msg.sender.transfer(returnValue);
        // Obtener el balance de Tokens del contrato 
        uint Balance = TokensDisponibles();
        // Filtro para evaluar los tokens a comprar con los tokens disponibles 
        require (_numTokens <= Balance, "Compra un numero de Tokens adecuado.");
        // Tranferencia de Tokens al comprador 
        token.transfer(msg.sender, _numTokens);
        // Emitir el evento de compra tokens 
        emit ComprandoTokens(_numTokens, msg.sender);
    }
    
    // Balance de tokens en el contrato de loteria 
    function TokensDisponibles() public view returns (uint) {
        return token.balanceOf(contrato);
    }
    
    // Obtener el balance de tokens acumulados en el Bote 
    function Bote() public view returns (uint) {
        return token.balanceOf(owner);
    }
    
    // Balance de Tokens de una persona 
    function MisTokens() public view returns (uint) {
        return token.balanceOf(msg.sender);
    }
    
    // ----------------------------------------  LOTERIA ----------------------------------------
    
    // Precio del boleto en Tokens 
    uint public PrecioBoleto = 5;
    // Relacion entre la persona que compra los boletos y los numeros de los boletos
    mapping (address => uint []) idPersona_boletos;
    // Relacion necesaria para identificar al ganador 
    mapping (uint => address) ADN_boleto;
    // Numero aleatorio 
    uint randNonce = 0;
    // Boletos generados 
    uint [] boletos_comprados;
    // Eventos 
    event boleto_comprado(uint,address);   // Evento cuando se compra un boleto
    event boleto_ganador(uint);            // Evento del ganador
    event tokens_devueltos(uint,address);  // Evento para devolver tokens
    
    // Funcion para comprar boletos de loteria 
    function CompraBoleto(uint _boletos) public {
        // Precio total de los boletos a comprar
        uint precio_total = _boletos*PrecioBoleto;
        // Filtrado de los tokens a pagar 
        require (precio_total <= MisTokens(), "Necesitas comprar mas tokens.");
        // Transferencia de tokens al owner -> bote/premio
        /* El cliente paga la atraccion en Tokens:
        - Ha sido necesario crear una funcion en ERC20.sol con el nombre de: 'transferencia_loteria'
        debido a que en caso de usar el Transfer o TransferFrom las direcciones que se escogian 
        para realizar la transccion eran equivocadas. Ya que el msg.sender que recibia el metodo Transfer o
        TransferFrom era la direccion del contrato. Y debe ser la direccion de la persona fisia.
        */
        token.transferencia_loteria(msg.sender, owner, precio_total);
        /*
        Lo que esto haria es tomar la marca de tiempo now, el msg.sender y un nonce
        (un numero que solo se utiliza una vez, para que no ejecutemos dos veces la misma 
        funcion de hash con los mismos parametros de entrada) en incremento.
        Luego se utiliza keccak256 para convertir estas entradas a un hash aleatorio, 
        convertir ese hash a un uint y luego utilizamos % 10000 para tomar los ultimos 4 digitos.
        Dando un valor aleatorio entre 0 - 9999.
        */
        for (uint i = 0; i < _boletos; i++) {
            uint random = uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % 10000;
            randNonce++;
            // Almacenamos los datos de los boletos 
            idPersona_boletos[msg.sender].push(random);
            // Numero de boleto comprado
            boletos_comprados.push(random);
            // Asignacion del ADN del boleto para tener un ganador 
            ADN_boleto[random] = msg.sender;
            // Emision del evento 
            emit boleto_comprado(random , msg.sender);
        }
        
    }
    
    // Visualizar el numero de boletos de una persona
    function TusBoletos() public view returns (uint [] memory){
        return idPersona_boletos[msg.sender];
    }
    
    // Funcion para generar un ganador y ingresarle los Tokens 
    function GenerarGanador() public Unicamente(msg.sender) {
        // Debe haber boletos comprados para generar un ganador 
        require(boletos_comprados.length > 0, "No hay boletos comprados");
        // Declaracion de la longitud del array 
        uint longitud = boletos_comprados.length;
        // Aleatoriamente elijo un numero entre: 0 - Longitud 
        // 1 - Eleccion de una posicion aleatoria del array 
        uint posicion_array = uint(uint(keccak256(abi.encodePacked(now))) % longitud);
        // 2- Seleccion del numero aleatorio mediante la posicion del array aleatoria
        uint eleccion = boletos_comprados[posicion_array];
        // Emision del evento del ganador 
        emit boleto_ganador(eleccion);
        // Recuperar la direccion del ganador 
        address direccion_ganador = ADN_boleto[eleccion];
        // Enviarle los tokens del premio al ganador 
        token.transferencia_loteria(msg.sender, direccion_ganador, Bote());
    }
    
    // Devolucion de los tokens 
    function DevolverTokens(uint _numTokens) public payable {
        // El numero de tokens a devolver debe ser mayor a 0 
        require(_numTokens > 0 , "Necesitas devolver un numero positivo de tokens.");
        // El usuario/cliente debe tener los tokens que desea devolver 
        require (_numTokens <= MisTokens(), "No tienes los tokens que deseas devolver.");
        // DEVOLUCION:
        // 1. El cliente devuelva los tokens
        // 2. La loteria paga los tokens devueltos en ethers
        token.transferencia_loteria(msg.sender, address(this), _numTokens);
        msg.sender.transfer(PrecioTokens(_numTokens));
        // Emision del evento 
        emit tokens_devueltos(_numTokens, msg.sender);
    }
    
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/OMS/oms.sol
================================================
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 < 0.9.0;
pragma experimental ABIEncoderV2;

contract OMS_COVID {
    
    // Direccion de la OMS -> Owner / Dueño del contrato 
    address public OMS;
    
    // Constructor del contrato 
    constructor () public {
        OMS = msg.sender;
    }
    
    // Mapping para relacionar los centros de salud (direccion/address) con la validez del sistema de gestion
    mapping (address => bool) public Validacion_CentrosSalud;
    
    // Relacionar una direccion de un centro de salud con su contrato 
    mapping (address => address) public CentroSalud_Contrato;
    
    // Ejmeplo 1: 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 -> true = TIENE PERMISOS PARA CREAR SU SMART CONTRACT
    // Ejmeplo 2: 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 -> false = NO TIENE PERMISOS PARA CREAR SU SMART CONTRACT
    
    // Array de direcciones que almacene los contratos de los centros de salud validados 
    address [] public direcciones_contratos_salud;
    
    // Array de las direcciones que soliciten acceso 
    address [] Solicitudes;
    
    // Eventos a emitir 
    event SolicitudAcceso (address);
    event NuevoCentroValidado (address);
    event NuevoContrato (address, address);
    
    
    // Modificador que permita unicamente la ejecucion de funciones por la OMS 
    modifier UnicamenteOMS(address _direccion) {
        require(_direccion == OMS, "No tienes permisos para realizar esta funcion.");
        _;
    }
    
    // Funcion para solicitar acceso al sistema medico 
    function SolicitarAcceso() public {
        // Almacenar la direccion en el array de solicitudes 
        Solicitudes.push(msg.sender);
        // Emision del evento 
        emit SolicitudAcceso (msg.sender);
    }
    
    // Funcion que visualiza las direcciones que han solicitado este acceso 
    function VisualizarSolicitudes() public view UnicamenteOMS(msg.sender) returns (address [] memory){
        return Solicitudes;
    }
    
    // Funcion para validar nuevos centros de salud que puedan autogestionarse -> UnicamenteOMS
    function CentrosSalud (address _centroSalud) public UnicamenteOMS(msg.sender) {
        // Asignacion del estado de validez al centro de salud 
        Validacion_CentrosSalud[_centroSalud] = true;
        // Emision del evento 
        emit NuevoCentroValidado(_centroSalud);
    }
    
    
    // Funcion que permita crear un contrato inteligente de un centro de salud 
    function FactoryCentroSalud() public {
        // Filtrado para que unicamente los centros de salud validados sean capaces de ejecutar esta funcion 
        require (Validacion_CentrosSalud[msg.sender] == true, "No tienes permisos para ejecutar esta funcion.");
        // Generar un Smart Contract -> Generar su direccion 
        address contrato_CentroSalud = address (new CentroSalud(msg.sender));
        // Almacenamiento la direccion del contrato en el array 
        direcciones_contratos_salud.push(contrato_CentroSalud);
        // Relacion entre el centro de salud y su contrato 
        CentroSalud_Contrato[msg.sender] = contrato_CentroSalud;
        // Emisio del evento 
        emit NuevoContrato(contrato_CentroSalud, msg.sender);
    }
    
    
}


// Contrato autogestionable por el Centro de Salud 
contract CentroSalud {
    
    // Direcciones iniciales 
    address public DireccionCentroSalud;
    address public DireccionContrato;
    
    constructor (address _direccion) public {
        DireccionCentroSalud = _direccion;
        DireccionContrato = address(this);
    }
    
    // Mapping para relacionar el hash de la persona con los resultados (diagnostico, CODIGO IPFS)
    mapping (bytes32 => Resultados) ResultadosCOVID;
    
    // Estructura de los resultados 
    struct Resultados {
        bool diagnostico;
        string CodigoIPFS;
    }
    
    // Eventos
    event NuevoResultado (bool, string);
    
    // Filtrar las funciones a ejecutar por el centro de salud 
    modifier UnicamenteCentroSalud(address _direccion) {
        require (_direccion == DireccionCentroSalud, "No tienes permisos para ejecutar esta funcion.");
        _;
    }
    
    // Funcion para emitir un resultado de una prueba de COVID 
    // Formato de los campos de entrada: | 12345X | true | QmNZTbxobVxzsCv4uwvSrh5a8bw6zJKFmNYvKbeRdDrnjT
    function ResultadosPruebaCovid(string memory _idPersona, bool _resultadoCOVID, string memory _codigoIPFS) public UnicamenteCentroSalud(msg.sender){
        // Hash de la identificacion de la persona 
        bytes32 hash_idPersona = keccak256 (abi.encodePacked(_idPersona));
        // Relacion del hash de la persona con la estructura de resultados 
        ResultadosCOVID[hash_idPersona] = Resultados(_resultadoCOVID, _codigoIPFS);
        // Emision de un evento 
        emit NuevoResultado(_resultadoCOVID, _codigoIPFS);
    }
    
    // Funcion que permita la visualizacion de los resultados 
    function VisualizarResultados(string memory _idPersona) public view returns (string memory _resultadoPrueba, string memory _codigoIPFS) {
        // Hash de la identidad de la persona 
        bytes32 hash_idPersona = keccak256 (abi.encodePacked(_idPersona));
        // Retorno de un booleano como un string 
        string memory resultadoPrueba;
        if (ResultadosCOVID[hash_idPersona].diagnostico == true){
            resultadoPrueba = "Positivo";
        } else{
            resultadoPrueba = "Negativo";
        }
        // Retorno de los parametros necesarios
        _resultadoPrueba = resultadoPrueba;
        _codigoIPFS = ResultadosCOVID[hash_idPersona].CodigoIPFS;
    }
    
    
}


================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/VOTACION/votacion.sol
================================================
//SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// -----------------------------------
//  CANDIDATO   |   EDAD   |      ID
// -----------------------------------
//  Toni        |    20    |    12345X
//  Alberto     |    23    |    54321T
//  Joan        |    21    |    98765P
//  Javier      |    19    |    56789W


contract votacion{
    
    //Direccion del propietario del contrato
    address owner;
    
    //constructor
    constructor () public{
        owner = msg.sender;
    }
    
    //Relacion entre el nombre del candidato y el hash de sus datos personales
    mapping (string=>bytes32) ID_Candidato;
    
    //Relacion entre el nombre del candidato y el numero de votos
    mapping (string=>uint) votos_candidato;
    
    //Lista para almacenar los nombres de los candidatos
    string [] candidatos;
    
    //Lista de los hashes de la identidad de los votantes
    bytes32 [] votantes;
    
    
    //Cualquier persona puede usar esta funcion para presentarse a las elecciones
    function Representar(string memory _nombrePersona, uint _edadPersona, string memory _idPersona) public{
        
        //Hash de los datos del candidato
        bytes32 hash_Candidato = keccak256(abi.encodePacked(_nombrePersona, _edadPersona, _idPersona));
        
        //Almacenamos el hash de los datos del candidato ligados a su nombre
        ID_Candidato[_nombrePersona] = hash_Candidato;
        
        //Almacenamos el nombre del candidato
        candidatos.push(_nombrePersona);
        
    }
    
    //Permite visualizar las personas que se han presentado como candidatos a las votaciones
    function VerCandidatos() public view returns(string[] memory){
        //Devuelve la lista de los candidatos presentados
        return candidatos;
    }
    
    //Los votantes van a poder votar
    function Votar(string memory _candidato) public{
        
        //Hash de la direccion de la persona que ejecuta esta funcion
        bytes32 hash_Votante = keccak256(abi.encodePacked(msg.sender));
        //Verificamos si el votante ya ha votado
        for(uint i=0; i<votantes.length; i++){
            require(votantes[i]!=hash_Votante, "Ya has votado previamente");
        }
        //Almacenamos el hash del votante dentro del array de votantes
        votantes.push(hash_Votante);
        //Añadimos un voto al candidato seleccionado
        votos_candidato[_candidato]++;
    }
    
    //Dado el nombre de un candidato nos devuelve el numero de votos que tiene
    function VerVotos(string memory _candidato) public view returns(uint){
        //Devolviendo el numero de votos del candidato _candidato
        return votos_candidato[_candidato];
    }
    
    //Funcion auxiliar que transforma un uint a un string
    function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
        if (_i == 0) {
            return "0";
        }
        uint j = _i;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (_i != 0) {
            bstr[k--] = byte(uint8(48 + _i % 10));
            _i /= 10;
        }
        return string(bstr);
    }
    
    
    //Ver los votos de cada uno de los candidatos
    function VerResultados() public view returns(string memory){
        //Guardamos en una variable string los candidatos con sus respectivos votos
        string memory resultados="";
        
        //Recorremos el array de candidatos para actualizar el string resultados
        for(uint i=0; i<candidatos.length; i++){
            //Actualizamos el string resultados y añadimos el candidato que ocupa la posicion "i" del array candidatos
            //y su numero de votos
            resultados = string(abi.encodePacked(resultados, "(", candidatos[i], ", ", uint2str(VerVotos(candidatos[i])), ") -----"));
        }
        
        //Devolvemos los resultados
        return resultados;
    }
    
    //Proporcionar el nombre del candidato ganador
    function Ganador() public view returns(string memory){
        
        //La variable ganador contendra el nombre del candidato ganador 
        string memory ganador= candidatos[0];
        bool flag;
        
        //Recorremos el array de candidatos para determinar el candidato con un numero de votos mayor
        for(uint i=1; i<candidatos.length; i++){
            
            if(votos_candidato[ganador] < votos_candidato[candidatos[i]]){
                ganador = candidatos[i];
                flag=false;
            }else{
                if(votos_candidato[ganador] == votos_candidato[candidatos[i]]){
                    flag=true;
                }
            }
        }
        
        if(flag==true){
            ganador = "¡Hay empate entre los candidatos!";
            
        }
        return ganador;
    }
}

================================================
FILE: BLOQUE 2 - Proyectos reales con Smart Contracts/VOTACION/votacion_tarea.sol
================================================
//SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// -----------------------------------
//  CANDIDATO   |   EDAD   |      ID
// -----------------------------------
//  Toni        |    20    |    12345X
//  Alberto     |    23    |    54321T
//  Joan        |    21    |    98765P
//  Javier      |    19    |    56789W


contract votacion{
    
    //Direccion del propietario del contrato
    address owner;
    
    //Almacenamos el valor de tiempo en que empiezan las elecciones
    uint empiezan_votaciones;
    
    //constructor
    constructor () public{
        owner = msg.sender;
        empiezan_votaciones = now;
    }
    
    //Relacion entre el nombre del candidato y el hash de sus datos personales
    mapping (string=>bytes32) ID_Candidato;
    
    //Relacion entre el nombre del candidato y el numero de votos
    mapping (string=>uint) votos_candidato;
    
    //Lista para almacenar los nombres de los candidatos
    string [] candidatos;
    
    //Lista de los hashes de la identidad de los votantes
    bytes32 [] votantes;
    
    
    //Cualquier persona puede usar esta funcion para presentarse a las elecciones
    function Representar(string memory _nombrePersona, uint _edadPersona, string memory _idPersona) public{
        
        //Tenemos la mitad del tiempo total para que se presenten candidatos
        require(now<=(empiezan_votaciones + 1 minutes)/2, "Ya no se pueden presentar candidatos");
        
        //Hash de los datos del candidato
        bytes32 hash_Candidato = keccak256(abi.encodePacked(_nombrePersona, _edadPersona, _idPersona));
        
        //Almacenamos el hash de los datos del candidato ligados a su nombre
        ID_Candidato[_nombrePersona] = hash_Candidato;
        
        //Almacenamos el nombre del candidato
        candidatos.push(_nombrePersona);
        
    }
    
    //Permite visualizar las personas que se han presentado como candidatos a las votaciones
    function VerCandidatos() public view returns(string[] memory){
        //Devuelve la lista de los candidatos presentados
        return candidatos;
    }
    
    //Los votantes van a poder votar
    function Votar(string memory _candidato) public{
        
        //Solamente se puede votar dentro del periodo de votacion
        require(now<=empiezan_votaciones + 1 minutes, "Ya no se puede votar");
        
        //Hash de la direccion de la persona que ejecuta esta funcion
        bytes32 hash_Votante = keccak256(abi.encodePacked(msg.sender));
        //Verificamos si el votante ya ha votado
        for(uint i=0; i<votantes.length; i++){
            require(votantes[i]!=hash_Votante, "Ya has votado previamente");
        }
        //Almacenamos el hash del votante dentro del array de votantes
        votantes.push(hash_Votante);
        
        //Verificamos que el candidato esta en la lista de candidatos
        
        //La variable flag sera true si el candidato esta en la lista
        bool flag = false;
        
        for(uint j=0; j<candidatos.length; j++){
            //Comparamos el nombre del candidato con el nombre del candidato en la posicion i
            if(keccak256(abi.encodePacked(candidatos[j])) == keccak256(abi.encodePacked(_candidato))){
                //Si coinciden cambiamos el valor de flag
                flag=true;
            }
        }
        //Es necesario que el candidato este en la lista para poder votar
        require(flag==true, "No hay ningun candidato con ese nombre");
        
        //Añadimos un voto al candidato seleccionado
        votos_candidato[_candidato]++;
    }
    
    //Dado el nombre de un candidato nos devuelve el numero de votos que tiene
    function VerVotos(string memory _candidato) public view returns(uint){
        //Devolviendo el numero de votos del candidato _candidato
        return votos_candidato[_candidato];
    }
    
    //Funcion auxiliar que transforma un uint a un string
    function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
        if (_i == 0) {
            return "0";
        }
        uint j = _i;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (_i != 0) {
            bstr[k--] = byte(uint8(48 + _i % 10));
            _i /= 10;
        }
        return string(bstr);
    }
    
    
    //Ver los votos de cada uno de los candidatos
    function VerResultados() public view returns(string memory){
        //Guardamos en una variable string los candidatos con sus respectivos votos
        string memory resultados="";
        
        //Recorremos el array de candidatos para actualizar el string resultados
        for(uint i=0; i<candidatos.length; i++){
            //Actualizamos el string resultados y añadimos el candidato que ocupa la posicion "i" del array candidatos
            //y su numero de votos
            resultados = string(abi.encodePacked(resultados, "(", candidatos[i], ", ", uint2str(VerVotos(candidatos[i])), ") -----"));
        }
        
        //Devolvemos los resultados
        return resultados;
    }
    
    //Proporcionar el nombre del candidato ganador
    function Ganador() public view returns(string memory){
        
        //No se puede ejecutar la funcion hasta que terminan las votaciones
        require(now>(empiezan_votaciones + 1 minutes), "Todavia no han terminado las votaciones");
        
        //La variable ganador contendra el nombre del candidato ganador 
        string memory ganador= candidatos[0];
        bool flag;
        
        //Recorremos el array de candidatos para determinar el candidato con un numero de votos mayor
        for(uint i=1; i<candidatos.length; i++){
            
            if(votos_candidato[ganador] < votos_candidato[candidatos[i]]){
                ganador = candidatos[i];
                flag=false;
            }else{
                if(votos_candidato[ganador] == votos_candidato[candidatos[i]]){
                    flag=true;
                }
            }
        }
        
        if(flag==true){
            ganador = "¡Hay empate entre los candidatos!";
            
        }
        return ganador;
    }

================================================
FILE: BLOQUE 3 - Proyecto final de curso/PROYECTO FINAL - Servicio de telemedicina/ERC20.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;
import "./SafeMath.sol";


interface IERC20{
    function totalSupply() external view returns (uint256);
    function balanceOf (address account) external view returns (uint256);
    function allowance(address owner,address spender) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function approve (address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval (address indexed owner, address indexed spender, uint256 value);
}

contract ERC20Basic is IERC20 {
    string public constant name = "ERC20Basic";
    string public constant symbol = "JBJ-TOKEN";
    uint8 public constant decimals = 2;
    
    event Transfer(address indexed from, address indexed to, uint256 tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
    
    mapping (address => uint) balances;
    mapping(address => mapping (address => uint)) allowed;
    uint256 totalSupply_;
    
    using SafeMath for uint256;
    
    constructor (uint256 total) public{
        totalSupply_ = total;
        balances[msg.sender] = totalSupply_;
    }
    
    function totalSupply() public override view returns (uint256){
        return totalSupply_;
    }
    
    function increaseTotalSuply(uint newTokens) public{
        totalSupply_ += newTokens;
        balances[msg.sender] += newTokens;
    }
    
    function balanceOf (address tokenOwner) public override view returns (uint256){
        return balances[tokenOwner];
    }
    
    function transfer(address receiver, uint256 numTokens) public override returns (bool){
        require(numTokens <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(msg.sender,receiver,numTokens);
        return true;
    } 
    
    
    function approve (address delegate, uint256 numTokens) public override returns (bool) {
        allowed[msg.sender][delegate] = numTokens;
        emit Approval(msg.sender, delegate, numTokens);
        return true;
    }
    
    function allowance (address owner, address delegate) public override view returns (uint){
        return allowed[owner][delegate];
    }
    
    function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool){
        require (numTokens <= balances[owner]);
        require (numTokens <= allowed[owner][msg.sender]);
        
        balances[owner] = balances[owner].sub(numTokens);
        allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(owner,buyer,numTokens);
        return true;
    }
    
}

================================================
FILE: BLOQUE 3 - Proyecto final de curso/PROYECTO FINAL - Servicio de telemedicina/MedicalInsurance.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;
import "./OperacionesBasicas.sol";
import "./ERC20.sol";

// Contrato para la Compañia de Seguros
contract InsuranceFactory is OperacionesBasicas{
    
    // Constructor de Insurance Factory
    constructor () public{
        token = new ERC20Basic(100);
        Insurance = address(this);
        Aseguradora = msg.sender;
        }
        
     /* Una de las estructuras de datos para IF son los clientes donde se guarda su direccion, y
     la autorizacion de este por su policía. Por otra parte, los servicios de los que
     se guarda el nombre de este servicio, el precio en tokens y el estado del servicio. También disponemos de una estructura
     de datos del laboratorio donde se guarda toda la información necesaria de este laboratorio como puede ser
     su direccion y el booleano de si es válido o no lo es. */
        
        //Estructura del cliente
        struct cliente {
            address DireccionCliente;
            bool AutorizacionCliente;
            address DireccionContrato;
        }
        
        //Estructura del servicio
        struct servicio{
            string nombreServicio;
            uint precioTokensServicio;
            bool EstadoServicio;
        }
        
         //Estructura del laboratorio
        struct lab {
            address direccionContratoLab;
            bool ValidacionLab;
        }
        
        // Instancia del contrato token
        ERC20Basic private token;
        
        // Declaraciones de las direcciones
        address Insurance;
        address payable public Aseguradora;
        
        // Array para guardas les direcciones de los asegurados
        address [] DireccionesAsegurados;
        
        //Mapping para relacionar una direccion y una estructura de un cliente
        mapping (address => cliente) public MappingAsegurados;
        
        //Mapping para relacionar un string y un servicio
        mapping (string => servicio) public MappingServicios;
        
        //Array para guardar los nombres de los servicios 
        string [] private nombreServicios;
        
         // Array para guardar las direcciones de los laboratorios 
        address [] DireccionesLaboratorios;
        
        // Modificadores que permiten unicamente realizar funciones a los asegurados
        modifier UnicamenteAsegurado(address _direccionAsegurado){
            // Se requiere que la direccion este autorizada previamente
            FuncionUnicamenteAsegurado(_direccionAsegurado);
            _;
        }
        
        // Funcion para ejecutar una PCR o una RX por un asegurado en un laboratorio
        function FuncionUnicamenteAsegurado(address _direccionAsegurado) public view{
            require (MappingAsegurados[_direccionAsegurado].AutorizacionCliente == true, "Direccion no autorizada.");
        }
        
        // Restricciones para que unicamente se ejecuten funciones por la compañia de seguros
        modifier UnicamenteAseguradora(address _direccionAsseguradora){
            // Es requreix que l'adreça de l'asseguradora sigui l'unicada autoritzada
            require (Aseguradora == _direccionAsseguradora, "Direccion no autorizada.");
            _;
        }
        
        // Restricciones para que unicamente el asegurado o la compañia de seguros ejecute funciones
        modifier Asegurado_o_Aseguradora(address _direccionAsegurado, address _direccionEntrante){
            require ((MappingAsegurados[_direccionEntrante].AutorizacionCliente == true 
                && _direccionAsegurado == _direccionEntrante) || Aseguradora == _direccionEntrante, 
                    "Unicamente compañia de seguros y asegurados");
            _;
        }
        
        // Eventos
        event EventoComprado (uint256);
        event EventoServicioProporcionado (address, string, uint256);
        event LaboratorioCreado (address, address);
        event AseguradoCreado (address, address);
        event EventoBajaCliente(address);
        event EventoNuevoServicio(string, uint256);
        event EventoBajaServicio(string);
        
        // Mapping para relacionar direcciones con laboratorios
        mapping (address => lab) public MappingLab;
        
        /*Funcion para llevar a cabo la creación de un contrato por un laboratorio.
        Esta función la podrá ejecutar cualquier persona */
        function creacionLab() public {
            // Se guarda la direccion del laboratorio en un array
            DireccionesLaboratorios.push(msg.sender);
            // Se crea un contrato para un laboratorio 
            address direccionLab = address(new Laboratorio(msg.sender, Insurance));
            /* Creación de la estructura del Laboratorio:
                 Asignación de la dirección del contrato del laboratorio a la estructura del laboratorio respectivo.
                 Asignación de la validacion positiva como laboratorio. */
            lab memory Laboratorio = lab(direccionLab, true);
            // Se guarda la esctructura de datos del laboratorio
            MappingLab[msg.sender] = Laboratorio;
            // Evento de la creacion del laboratorio
            emit LaboratorioCreado(msg.sender, direccionLab);
         }
        
         /* Funcion para llevar a cabo la creación de un contrato por un asegurado.
         Esta función la podrá ejecutar cualquier dirección. */
        function creacionContratoAsegurado() public {
            // Guarda la direccion del asegurado en un array
            DireccionesAsegurados.push(msg.sender);
            // Generacion de un contrato para el asegurado
            address direccionAsegurado = address(new InsuranceHealthRecord(msg.sender, token, Insurance, Aseguradora));
             // Almacenamiento de la informacion del aseguradora (cliente) en una estructura de datos
             MappingAsegurados[msg.sender] = cliente(msg.sender,true,direccionAsegurado);
             // Evento para informar del nuevo asegurado
             emit AseguradoCreado(msg.sender,direccionAsegurado);
        }
        
        // Funcion que devuelve el array de las direcciones de los laboratorios
        function Laboratorios() public view UnicamenteAseguradora(msg.sender) returns(address [] memory){
        return DireccionesLaboratorios;
        }
        
        // Funcion que devuelve el array de las direcciones de los Asegurados
        function Asegurados() public view UnicamenteAseguradora(msg.sender) returns(address [] memory){
        return DireccionesAsegurados;
        }
        
        // Funcion para ver el historial de un asegurado
        function consultarHistorialAsegurado(address _direccionAsegurado, address _direccionConsultor) public view Asegurado_o_Aseguradora(_direccionAsegurado, _direccionConsultor) returns(string memory){
            string memory historial = "";
            address direccionContratoAsegurado = MappingAsegurados[_direccionAsegurado].DireccionContrato;
            for(uint i = 0; i < nombreServicios.length; i++){
                if(MappingServicios[nombreServicios[i]].EstadoServicio && InsuranceHealthRecord(direccionContratoAsegurado).ServicioEstadoAsegurado(nombreServicios[i]) == true){
                    (string memory nombreServicio,uint precioServicio) = InsuranceHealthRecord(direccionContratoAsegurado).HistorialAsegurado(nombreServicios[i]);            
                    historial = string(abi.encodePacked(historial, "(", nombreServicio, ", ", uint2str(precioServicio), ") ------"));
                }
            }
            return historial;
        }        
        
        // Dar de baja a un asegurado
        function darBajaCliente(address _direccionAsegurado) public UnicamenteAseguradora(msg.sender) returns (string memory){
            // La autorizacion del aseguradora se anula
            MappingAsegurados[_direccionAsegurado].AutorizacionCliente = false;
            // Se llama al metodo self destruct del cliente y se da de baja el cliente relacionado a la dirección entrada para parametro
            InsuranceHealthRecord(MappingAsegurados[_direccionAsegurado].DireccionContrato).darBaja;
            // Emision del evento
            emit EventoBajaCliente(_direccionAsegurado);
        }
            
        // Funcion para la creación de un nuevo servicio de la aseguradora
        function nuevoServicio(string memory _nombreServicio, uint256 _precioServicio) public UnicamenteAseguradora(msg.sender){
            // Relacion con el nombre del nuevo servicio y la estructura definida del servicio (nombre, precio y estado)
            MappingServicios[_nombreServicio] = servicio(_nombreServicio,_precioServicio,true);
            // Se guarda el nombre del servicio en el array
            nombreServicios.push(_nombreServicio);
            // Evento de un nuevo servicio
            emit EventoNuevoServicio(_nombreServicio,_precioServicio);
        }
        
        // La aseguradora dar de baja un servicio dado de alta anteriormente
        function darBajaServicio(string memory _nombreServicio) public UnicamenteAseguradora(msg.sender){
            // El servicio debe haberse dado de alta antes para darlo de baja
            require(ServicioEstado(_nombreServicio) == true, "No se ha dado de alta el servicio.");
            // El estado del servicio pasa a estar de baja
            MappingServicios[_nombreServicio].EstadoServicio = false; 
            // Evento para emitir la baja del servicio
            emit EventoBajaServicio(_nombreServicio);
        }
        
        // Funcion para obtener el precio de un servicio si éste se encuentra activo
        function getPrecioServicio(string memory _nombreServicio) public view returns (uint256 tokens){
            // Se requiere que el servicio que pedimos esté dado de alta
            require(MappingServicios[_nombreServicio].EstadoServicio == true, "Servicio no disponible");
            // Devuelve el precio del servicio con la ayuda del mapping que relacionan el nombre con su estructura de datos
            return MappingServicios[_nombreServicio].precioTokensServicio;
        }
        
        // Funcion para devolver el estado del servicio (puede ser: true o false)
        function ServicioEstado(string memory _nombreServicio) public view returns (bool){
            return MappingServicios[_nombreServicio].EstadoServicio;
        }
        
        
        // Funcion para devolver todos los servicios activos de la aseguradora
        function ConsultarServiciosActivos() public view returns (string [] memory) {
        // Array para almacenar los servicios activos de la aseguradora
        string [] memory ServiciosActivos =  new string[](nombreServicios.length);
        uint contador = 0;
        // Procedimiento para ver qué servicios se encuentran activos del array de 'nombreServicios'
            for (uint i = 0; i< nombreServicios.length; i++){
                // Si el servicio está activo (true) se guarda dentro del nuevo array 'ServiciosActivos'
                if(ServicioEstado(nombreServicios[i]) == true){
                    ServiciosActivos[contador] = nombreServicios[i]; 
                    contador++;
                }
            }
            return ServiciosActivos;
        }
    
        
        // Función para la compra de Tokens mediante ether a través de la implementación del contrato del token
        function compraTokens(address _asegurado, uint _numTokens) public payable UnicamenteAsegurado(_asegurado) {
            // Se obtiene el número de tokens de lo dispuesto en el contrato
            uint256 Balance = balanceOf();
            
            /* Una vez tenemos el número de tokens de lo dispuesto, debemos establecer las condiciones adecuadas:
             1. El número de tokens que se quieren comprar debe ser menor o igual al número de tokens disponibles
             para ser comprados.
             2. El número de tokens a comprar debe ser positivo */
             
            require(_numTokens <= Balance, "Compra un numero de tokens adecuado");
            require(_numTokens > 0, "Compra un numero positivo de tokens");
            // El número de tokens se transfiere al asegurado que las ha comprado
            token.transfer(msg.sender, _numTokens);
            // Evento para emitir que se han comprado los número de tokens
            emit EventoComprado(_numTokens);
        }
        
        // La compañia puede incrementar el numero de tokens
        function generarTokens(uint _numTokens) public UnicamenteAseguradora(msg.sender) {
            token.increaseTotalSuply(_numTokens);
        }
        
        // Balance de tokens del contrato de la aseguradora
        function balanceOf() public view returns(uint256 tokens){
            return (token.balanceOf(address(this)));
        }
        
}
    
/* Contrato desplegado por el asegurado que le permite hacer toda la gestión requerida */
contract InsuranceHealthRecord is OperacionesBasicas{
    
    // Constructor del IHR 
    constructor (address _owner , IERC20 _token, address _insurance , address payable _aseguradora) public{
        propietario.direccionPropietario = _owner;
        propietario.saldoPropietario = 0;
        propietario.estado = Estado.alta;
        propietario.tokens = _token;
        propietario.insurance = _insurance;
        propietario.aseguradora = _aseguradora;
    }
    
    // Eventos requeridos para informar de la ejecución de ciertas funciones
    event servicioPagado (address, string, uint256);
    event EventoDevolverTokens(address, uint256);
    event EventoPeticionServicioLab(address, address,string);
    event EventoSelfDestruct(address);
    
    // Estado
    enum Estado {alta,baja}
    
    // Estructura de los servicios solicitados
    struct ServiciosSolicitados{
        string nombreServicio;
        uint256 precioServicio;
        bool estadoServicio;
    }
    
    // Estructura de los servicios solicitados del laboratorio (PCR o RX)
    struct ServicioSolicitadoLab{
        string nombreServicio;
        uint256 precioServicio;
        address direccionLab;
    }
    
    // Mapping para guardar el historial del asegurado
    mapping (string => ServiciosSolicitados) historialAsegurado;
    
    // Mapping para guardar el historial del asegurado con los laboratorio
    ServicioSolicitadoLab [] historialAseguradoLaboratorio;
    
    // Estructura del propietario
    struct Owner{
        address direccionPropietario;
        uint saldoPropietario;
        Estado estado;
        IERC20 tokens;
        address insurance;
        address payable aseguradora;
    }
    
    // Modifier para controlar que unicamente el propietario de la póliza puede ejecutar ciertas funciones
    modifier Unicamente(address _direccion){
        require (_direccion == propietario.direccionPropietario, "No eres un asegurado.");
        _;
    }
    
    // Estructura para almacenar información del propietario de la póliza
    Owner propietario;
    // Estructura para almacenar información de los servicios solicitados
    ServiciosSolicitados servicios;
       
    // Funcion para que un asegurado compre tokens
    function CompraTokens (uint _numTokens) payable public Unicamente(msg.sender){
        // Se requiere que el numero de tokens comprados sea positivo
        require (_numTokens > 0, "Necesitas comprar un numero de tokens positivo.");
        // Transferencia de los tokens
        uint coste = calcularPrecioTokens(_numTokens);
        require(msg.value >= coste, "Compra menos tokens o pon más ethers.");
        uint returnValue = msg.value - coste;
        msg.sender.transfer(returnValue);
        // Se llama a la función de compra de tokens del contrato IF
        InsuranceFactory(propietario.insurance).compraTokens(msg.sender, _numTokens);
    }
    
    // La función 'balance Of' devuelve el saldo del propietario, únicamente la puede ejecutar la cuenta del msg.sender
    function balanceOf() public view Unicamente(msg.sender) returns (uint256 _balance) {
        return (propietario.tokens.balanceOf(address(this)));
    }

    // Funcion para que un aseguradora devuelva tokens i recupere su valor en ethers
    function devolverTokens(uint _numTokens) public payable Unicamente(msg.sender){
        // El numero de tokens a devolver debe ser positivo 
        require (_numTokens > 0, "Necesitas devolver un numero positivo de tokens.");
        // El usuario debe tener el número de tokens que desea devolver
        require(_numTokens <= balanceOf(), "No tienes los tokens que desea devolver.");
        // El propietario devuelve los tokens
        propietario.tokens.transfer(propietario.aseguradora, _numTokens);
        // Devolucion al asegurado
        msg.sender.transfer(calcularPrecioTokens(_numTokens)); 
        // Evento que informa del retorno de tokens del msg.sender
        emit EventoDevolverTokens(msg.sender, _numTokens);
    }
    
    // Función para hacer la petición de un servicio a la aseguradora 
     function peticionServicio(string memory _servicio) public Unicamente(msg.sender){
        // Se comprueba que el servicio esté dado de alta
        require(InsuranceFactory(propietario.insurance).ServicioEstado(_servicio) == true, "El servicio no se ha dado de alta.");
        // Se obtiene el precio del servicio a partir del otro contrato IF
        uint256 pagamientoTokens = InsuranceFactory(propietario.insurance).getPrecioServicio(_servicio);
        // Es necesario que el precio del servicio sea menor al número de tokens de lo dispuesto
        require(pagamientoTokens <= balanceOf(), "Necesitas comprar más tokens para obtener este servicio");
        // Se envían los tokens que vale el servicio a la aseguradora (persona)
        propietario.tokens.transfer(propietario.aseguradora, pagamientoTokens);
        // Relacion con el nombre del nuevo servicio y la estructura definida de los servicios solicitados
        historialAsegurado[_servicio] = ServiciosSolicitados(_servicio,pagamientoTokens,true);
        // Evento para avisar de que el servicio se ha pagado
        emit servicioPagado (msg.sender, _servicio, pagamientoTokens);
    }
    

    /* El usuario hace la petición de un servicio a un laboratorio indicado a través de su dirección (pasada por parámetro) y el nombre
     del servicio que pide. Únicamente podrá ejecutar esta función el asegurado propietario de este contrato. */
    function peticionServicioLab(address _direccionLab, string memory _servicio) public payable Unicamente(msg.sender){
        // Instancia del contrato del Laboratorio que tiene por dirección 'dirección Lab'
        Laboratorio contratoLab = Laboratorio(_direccionLab);
        // Es necesario hacer un require para diferenciar los ethers y los tokens del asegurado
        require(msg.value == contratoLab.ConsultarPrecioServicios(_servicio) * 1 ether, "Operación no válida.");
        // Se da el servicio al asegurado
        contratoLab.DarServicio(msg.sender, _servicio);
        // Se paga el servicio al Laboratorio (cuenta, no contrato)
        payable(contratoLab.DireccionLab()).transfer(contratoLab.ConsultarPrecioServicios(_servicio) * 1 ether);
        // Se actualiza el historial de operaciones con Laboratorios del asegurado
        ServicioSolicitadoLab memory nuevoServicio = ServicioSolicitadoLab(_servicio, contratoLab.ConsultarPrecioServicios(_servicio), _direccionLab);
        historialAseguradoLaboratorio.push(nuevoServicio);
        // Evento que informa de la peticion del servicio
        emit EventoPeticionServicioLab(_direccionLab,msg.sender,_servicio);
    }
    
    // Funcion para ver el historial de los servicios de la aseguradora que ha consumido el asegurado
    function HistorialAseguradora() public view Unicamente(msg.sender) returns(string memory) {
        return InsuranceFactory(propietario.insurance).consultarHistorialAsegurado(msg.sender, msg.sender);
    }
    
    // Funcion para ver el historial del asegurado dado el nombre de un servicio por parametro (Función de ayuda para IF)
    function HistorialAsegurado(string memory _servicio) public view returns (string memory nombreServicio,uint precioServicio){
        return (historialAsegurado[_servicio].nombreServicio, historialAsegurado[_servicio].precioServicio);
    }
    
    // Funcion para ver el historial del asegurado dado el nombre de un servicio para parametro
    function HistorialAseguradoLaboratorio() public view returns (ServicioSolicitadoLab[] memory){
        return historialAseguradoLaboratorio;
    }
    
    // Funcion para devolver el estado del servicio (puede ser: true o false)
        function ServicioEstadoAsegurado(string memory _nombreServicio) public view returns (bool){
            return historialAsegurado[_nombreServicio].estadoServicio;
        }

    // El usuario se da de baja y utiliza 'self Destruct' para destruir su contrato
    function darBaja() public Unicamente(msg.sender){
        // Evento de la baja del cliente
        emit EventoSelfDestruct(msg.sender);
        // Destruccion del contrato del usuario
        selfdestruct(msg.sender); 
    }
    
}
        
// Contrato del laboratorio que da los servicios de PCR y RX
contract Laboratorio is OperacionesBasicas {
    
    // Direcciones necesarias  
    address public DireccionLab;
    address contratoAseguradora;
    
    // Constructor del laboratorio
    constructor (address _account, address _direccionContratoAseguradora) public {
        DireccionLab = _account;
        contratoAseguradora = _direccionContratoAseguradora;
    }
    
    // Relacion entre el asegurado y el servicio que ha solicitado
    mapping (address => string) public ServicioSolicitado;
    
    // Direcciones de las personas que han solicitado un servicio
    address [] public PeticionesServicios;
    
    // Relacion entre el asegurado y sus resultados del Servicio 
    mapping (address => ResultadoServicio) ResultadosServiciosLab;
    
    // Estructura del resultado de un servicio
    struct ResultadoServicio {
        string diagnostico_servicio;
        string codigo_IPFS;
    }
    
    // Estrucura del servicio ofrecido por el laboratorio
    struct ServicioLab{
        string nombreServicio;
        uint precio;
        bool enFuncionamiento;
    }

    // Array de los servicios que estan en funcionamiento 
    string [] nombreServiciosLab;
    
    // Mapping que relaciona el nombre del servicio con la estructura de datos del servicio 
    mapping (string => ServicioLab) public serviciosLab;
    
    
    // Eventos 
    event Evento_ServicioFuncionando (string,uint);
    event Evento_DarServicio (address,string);
    
    // Restriccion para que unicamente el laboratorio pueda ejecutar ciertas funciones
    modifier UnicamenteLab(address _direccion){
        require (_direccion == DireccionLab, "No existen permisos para ejecutar esta funcion.");
        _;
    } 
    
    // Se devuelve el conjunto de servicios que se encuentran en funcionamiento en el laboratorio
    function ConsultarServicios() public view returns (string [] memory){
        return nombreServiciosLab;
    }
    
    // Se devuelve el precio del servicio dado su nombre
    function ConsultarPrecioServicios(string memory _nombreServicio) public view returns (uint){
        return serviciosLab[_nombreServicio].precio;
    }

    // Funcion para dar un nuevo servicio de alta
    function NuevoServicioLab(string memory _servicio, uint _precio) public UnicamenteLab(msg.sender){
        // Creacion de un nuevo servicio 
        serviciosLab[_servicio] = ServicioLab(_servicio, _precio, true);
        // Se guarda en el array de servicios en funcionamiento
        nombreServiciosLab.push(_servicio);
        // Evento del servicio
        emit Evento_ServicioFuncionando(_servicio,_precio);
    }
    
    // Funcion para dar un servicio a un asegurado 
    function DarServicio(address _direccionAsegurado, string memory _servicio) public {
        // Se requiere que la persona que ejecuta la función sea un asegurado de la aseguradora
        InsuranceFactory IF = InsuranceFactory(contratoAseguradora);
        IF.FuncionUnicamenteAsegurado(_direccionAsegurado);
        // Se require que el servicio este activo
        require(serviciosLab[_servicio].enFuncionamiento == true, "El servicio no esta activo");
        // Relacion entre la persona y el servicio solicitado 
        ServicioSolicitado[_direccionAsegurado] = _servicio;
        // Almacenamos las personas que piden un servicio
        PeticionesServicios.push(_direccionAsegurado);
        // Emision del servicio 
        emit Evento_DarServicio (_direccionAsegurado, _servicio);
    }
  
    // Funcion para que el laboratorio pueda asignar los resultados al asegurado
    function DarResultados(address _direccionAsegurado, string memory _diagnostico, string memory _codigoIPFS) public UnicamenteLab(msg.sender){
        // Uso del mapping que relaciona un asegurado con la estructura de resultados
        ResultadosServiciosLab[_direccionAsegurado] = ResultadoServicio (_diagnostico, _codigoIPFS);
    }
    
    // Funcion para visualizar los resultados del servio solicitado por el asegurado
    function VisualizarResultados(address _direccionAsegurado) public view returns (string memory _diagnostico, string memory _codigoIPFS) {
        // Diagnostico del servicio
        _diagnostico = ResultadosServiciosLab[_direccionAsegurado].diagnostico_servicio;
        // Codigo IPFS del serviciop
        _codigoIPFS = ResultadosServiciosLab[_direccionAsegurado].codigo_IPFS;
    }
    

}

================================================
FILE: BLOQUE 3 - Proyecto final de curso/PROYECTO FINAL - Servicio de telemedicina/OperacionesBasicas.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;
import "./SafeMath.sol";

contract OperacionesBasicas{
    
    using SafeMath for uint256;
    
    //Contrato abstracto
    constructor() internal{}    
    
    function calcularPrecioTokens(uint _numTokens) internal pure returns (uint){
        return _numTokens.mul(1 ether);
    }
    
    function getBalance() public view returns(uint ethers){
        return payable(address(this)).balance;
    }
    
    // Funcion para pasar de uint a string
    function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
        if (_i == 0) {
            return "0";
        }
        uint j = _i;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (_i != 0) {
            bstr[k--] = byte(uint8(48 + _i % 10));
            _i /= 10;
        }
        return string(bstr);
    }
        
}


================================================
FILE: BLOQUE 3 - Proyecto final de curso/PROYECTO FINAL - Servicio de telemedicina/SafeMath.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.4 <0.7.0;
pragma experimental ABIEncoderV2;


// Implementacion de la libreria SafeMath para realizar las operaciones de manera segura
// Fuente: "https://gist.github.com/giladHaimov/8e81dbde10c9aeff69a1d683ed6870be"

library SafeMath{
    // Restas
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }
    
    // Sumas
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
    
    // Multiplicacion
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }
}


================================================
FILE: BLOQUE 4 - Creación de una Blockchain con Python/blockchain.ipynb
================================================
{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"blockchain.ipynb","provenance":[],"collapsed_sections":[],"authorship_tag":"ABX9TyNuXvlgmL/bGes6tD4jokf6"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"3c8EFe127W0U"},"source":["<div style=\"width: 100%; clear: both;\">\n","    <div style=\"float: left; width: 20%;\">\n","       <img src=\"https://joanamengualcom.files.wordpress.com/2021/11/blockstellart-2.png?w=100\", align=\"left\">\n","    </div>\n","</div>\n","\n","<div style=\"float: right; width: 50%;\">\n","    <p style=\"margin: 0; padding-top: 22px; text-align:right;\"> Construcción de mi Blockchain con Python</p>\n","    <p style=\"margin: 0; text-align:right;\">Formación en la Tecnología Blockchain</p>\n","    <p style=\"margin: 0; text-align:right; padding-button: 100px;\">Joan Amengual</p>\n","</div>\n","\n","</div>\n","<div style=\"width: 100%; clear: both;\">\n","<div style=\"width:100%;\">&nbsp;</div>"]},{"cell_type":"markdown","metadata":{"id":"oB1MtvWP_qNO"},"source":["Librerías necesarias para la creación de una Blockchain con Python:\n","\n","* **datetime**: El módulo datetime proporciona clases para manipular fechas y horas. Si bien la implementación permite operaciones aritméticas con fechas y horas, su principal objetivo es poder extraer campos de forma eficiente para su posterior manipulación o formateo.\n","\n","* **hashlib**: Este módulo implementa una interfaz común a diferentes algoritmos de hash y resúmenes de mensajes seguros. Están incluidos los algoritmos de hash FIPS seguros SHA1, SHA224, SHA226, SHA384 y SHA512 (definidos en FIPS 180-2) además del algoritmo MD5 de RSA (definido en Internet RFC 1321). Los términos «hash seguro» y «resumen de mensaje» son intercambiables. Los algoritmos más antiguos fueron denominados resúmenes de mensajes. El término moderno es hash seguro.\n","\n","* **json**: JSON son las siglas de JavaScript Object Notation. JSON es un formato de datos ligero que se utiliza para el intercambio de datos entre varios lenguajes diferentes. Es fácil de leer para los humanos y fácilmente analizado por las máquinas.\n","\n","* **flask**: Flask es un micro framework web escrito en Python. Se clasifica como un microframework porque no requiere herramientas o librerías particulares. No tiene capa de abstracción de base de datos, validación de formularios, o cualquier otro componente donde las librerías de terceros preexistentes proporcionan funciones comunes. Sin embargo, Flask admite extensiones que pueden añadir funciones a la aplicación como si estuvieran implementadas en el propio Flask. Existen extensiones para mapeadores objeto-relacionales, validación de formularios, manejo de cargas, varias tecnologías de autenticación abierta y varias herramientas relacionadas con el marco común.\n","\n","* **flask-ngrok**: Una forma sencilla de hacer demostraciones de aplicaciones Flask desde tu máquina. Hace que sus aplicaciones Flask que se ejecutan en localhost estén disponibles en Internet a través de la excelente herramienta ngrok."]},{"cell_type":"markdown","metadata":{"id":"zEMcysBgcfbv"},"source":["## Instalaciones"]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"VHidChooWq-v","executionInfo":{"status":"ok","timestamp":1638093671822,"user_tz":-60,"elapsed":4197,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"}},"outputId":"3211662b-2ee8-489a-cb0a-a68cbf08c283"},"source":["!pip install flask==0.12.2"],"execution_count":1,"outputs":[{"output_type":"stream","name":"stdout","text":["Collecting flask==0.12.2\n","  Downloading Flask-0.12.2-py2.py3-none-any.whl (83 kB)\n","\u001b[?25l\r\u001b[K     |████                            | 10 kB 16.9 MB/s eta 0:00:01\r\u001b[K     |████████                        | 20 kB 11.3 MB/s eta 0:00:01\r\u001b[K     |███████████▉                    | 30 kB 9.3 MB/s eta 0:00:01\r\u001b[K     |███████████████▉                | 40 kB 8.6 MB/s eta 0:00:01\r\u001b[K     |███████████████████▊            | 51 kB 5.0 MB/s eta 0:00:01\r\u001b[K     |███████████████████████▊        | 61 kB 5.2 MB/s eta 0:00:01\r\u001b[K     |███████████████████████████▋    | 71 kB 4.7 MB/s eta 0:00:01\r\u001b[K     |███████████████████████████████▋| 81 kB 5.2 MB/s eta 0:00:01\r\u001b[K     |████████████████████████████████| 83 kB 1.0 MB/s \n","\u001b[?25hRequirement already satisfied: itsdangerous>=0.21 in /usr/local/lib/python3.7/dist-packages (from flask==0.12.2) (1.1.0)\n","Requirement already satisfied: Jinja2>=2.4 in /usr/local/lib/python3.7/dist-packages (from flask==0.12.2) (2.11.3)\n","Requirement already satisfied: Werkzeug>=0.7 in /usr/local/lib/python3.7/dist-packages (from flask==0.12.2) (1.0.1)\n","Requirement already satisfied: click>=2.0 in /usr/local/lib/python3.7/dist-packages (from flask==0.12.2) (7.1.2)\n","Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.7/dist-packages (from Jinja2>=2.4->flask==0.12.2) (2.0.1)\n","Installing collected packages: flask\n","  Attempting uninstall: flask\n","    Found existing installation: Flask 1.1.4\n","    Uninstalling Flask-1.1.4:\n","      Successfully uninstalled Flask-1.1.4\n","Successfully installed flask-0.12.2\n"]}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"2mZZNqm6KB7d","executionInfo":{"status":"ok","timestamp":1638093701108,"user_tz":-60,"elapsed":3573,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"}},"outputId":"57fd1d4a-2ef1-4440-a4cd-4ac6e05e8121"},"source":["!pip install flask-ngrok==0.0.25"],"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["Collecting flask-ngrok==0.0.25\n","  Downloading flask_ngrok-0.0.25-py3-none-any.whl (3.1 kB)\n","Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from flask-ngrok==0.0.25) (2.23.0)\n","Requirement already satisfied: Flask>=0.8 in /usr/local/lib/python3.7/dist-packages (from flask-ngrok==0.0.25) (0.12.2)\n","Requirement already satisfied: Werkzeug>=0.7 in /usr/local/lib/python3.7/dist-packages (from Flask>=0.8->flask-ngrok==0.0.25) (1.0.1)\n","Requirement already satisfied: itsdangerous>=0.21 in /usr/local/lib/python3.7/dist-packages (from Flask>=0.8->flask-ngrok==0.0.25) (1.1.0)\n","Requirement already satisfied: click>=2.0 in /usr/local/lib/python3.7/dist-packages (from Flask>=0.8->flask-ngrok==0.0.25) (7.1.2)\n","Requirement already satisfied: Jinja2>=2.4 in /usr/local/lib/python3.7/dist-packages (from Flask>=0.8->flask-ngrok==0.0.25) (2.11.3)\n","Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.7/dist-packages (from Jinja2>=2.4->Flask>=0.8->flask-ngrok==0.0.25) (2.0.1)\n","Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->flask-ngrok==0.0.25) (2021.10.8)\n","Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->flask-ngrok==0.0.25) (1.24.3)\n","Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->flask-ngrok==0.0.25) (2.10)\n","Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->flask-ngrok==0.0.25) (3.0.4)\n","Installing collected packages: flask-ngrok\n","Successfully installed flask-ngrok-0.0.25\n"]}]},{"cell_type":"markdown","metadata":{"id":"YT9zNS_qcjPy"},"source":["## Mi Blockchain con Python"]},{"cell_type":"code","metadata":{"id":"5SbVk_mX7Bnl","executionInfo":{"status":"ok","timestamp":1638102049700,"user_tz":-60,"elapsed":297,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"}}},"source":["# Importación de las librerías\n","import datetime\n","import hashlib\n","import json\n","from flask       import Flask, jsonify\n","from flask_ngrok import run_with_ngrok"],"execution_count":8,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"ZkGBQ3P8DMn0"},"source":["Creación de una clase Blockchain que contenga todos los métodos esenciales, como son los siguientes:     \n","* Creación de un nuevo bloque\n","* Obtención del hash de un bloque\n","* Protocolo de concenso Proof of Work (PoW)\n","* Generación del hash de un bloque\n","* Verificación de la validez de la Blockchain"]},{"cell_type":"code","metadata":{"id":"ZxJK0C5H7HvM","executionInfo":{"status":"ok","timestamp":1638102055843,"user_tz":-60,"elapsed":263,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"}}},"source":["# Creación de la Blockchain\n","class Blockchain:\n","    \n","  def __init__(self):\n","    \"\"\" Constructor de la clase Blockchain. \"\"\"\n","\n","    self.chain = []\n","    self.create_block(proof = 1, previous_hash = '0')\n","      \n","  \n","  def create_block(self, proof, previous_hash):\n","    \"\"\" Creación de un nuevo bloque. \n","\n","      Arguments:\n","        - proof: Nounce del bloque actual. (proof != hash)\n","        - previous_hash: Hash del bloque previo.\n","\n","      Returns: \n","        - block: Nuevo bloque creado. \n","      \"\"\"\n","\n","    block = { 'index'         : len(self.chain)+1,\n","              'timestamp'     : str(datetime.datetime.now()),\n","              'proof'         : proof,\n","              'previous_hash' : previous_hash}\n","    self.chain.append(block)\n","    return block\n","\n","  def get_previous_block(self):\n","    \"\"\" Obtención del bloque previo de la Blockchain .\n","    \n","      Returns:\n","        - Obtención del último bloque de la Blockchain. \"\"\"\n","\n","    return self.chain[-1]\n","  \n","  def proof_of_work(self, previous_proof):\n","    \"\"\" Protocolo de concenso Proof of Work (PoW).\n","    \n","      Arguments:\n","        - previous_proof: Nounce del bloque previo.\n","\n","      Returns:\n","        - new_proof: Devolución del nuevo nounce obtenido con PoW. \"\"\"\n","\n","    new_proof = 1\n","    check_proof = False\n","    while check_proof is False:\n","        hash_operation = hashlib.sha256(str(new_proof**2 - previous_proof**2).encode()).hexdigest()\n","        if hash_operation[:4] == '0000':\n","            check_proof = True\n","        else: \n","            new_proof += 1\n","    return new_proof\n","  \n","  def hash(self, block):\n","    \"\"\" Cálculo del hash de un bloque.\n","    \n","    Arguments:\n","        - block: Identifica a un bloque de la Blockchain.\n","    \n","    Returns:\n","        - hash_block: Devuelve el hash del bloque \"\"\"\n","\n","    encoded_block = json.dumps(block, sort_keys = True).encode()\n","    hash_block = hashlib.sha256(encoded_block).hexdigest()\n","    return hash_block\n","  \n","  def is_chain_valid(self, chain):\n","    \"\"\" Determina si la Blockchain es válida. \n","    \n","    Arguments:\n","        - chain: Cadena de bloques que contiene toda la \n","                  información de las transacciones.\n","    \n","    Returns:\n","        - True/False: Devuelve un booleano en función de la validez de la \n","                      Blockchain. (True = Válida, False = Inválida) \"\"\"\n","\n","    previous_block = chain[0]\n","    block_index = 1\n","    while block_index < len(chain):\n","        block = chain[block_index]\n","        if block['previous_hash'] != self.hash(previous_block):\n","            return False\n","        previous_proof = previous_block['proof']\n","        proof = block['proof']\n","        hash_operation = hashlib.sha256(str(proof**2 - previous_proof**2).encode()).hexdigest()\n","        if hash_operation[:4] != '0000':\n","            return False\n","        previous_block = block\n","        block_index += 1\n","    return True"],"execution_count":9,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"rbwCOaUi-efe"},"source":["Aplicación Web accesible vía en modo de REST API. Mediante llamadas HTTP al REST API podemos establecer uan comunicación con el uso del módulo de Flask. \n","\n","Llamadas a realizar vía REST API:\n","* Minación de bloques: **mine_block()**\n","* Obtención de la Blockchain: **get_chain()**\n","* Comprobar estado de la Blockchain: **is_valid()**"]},{"cell_type":"code","metadata":{"id":"ldcYRB3q7Nj7","executionInfo":{"status":"ok","timestamp":1638102062705,"user_tz":-60,"elapsed":416,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"}}},"source":["# Crear una aplicación web\n","# Ejecución de la app con Notebook\n","app = Flask(__name__)\n","run_with_ngrok(app)  \n","\n","# Si se obtiene un error 500, actualizar flask y ejecutar la siguiente línea\n","app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False\n","\n","# Creación de la Blockchain\n","blockchain = Blockchain()\n","\n","\n","@app.route('/mine_block', methods=['GET'])\n","def mine_block():\n","  \"\"\" Minado de un nuevo bloque \"\"\"\n","\n","  previous_block  = blockchain.get_previous_block()\n","  previous_proof  = previous_block['proof']\n","  proof           = blockchain.proof_of_work(previous_proof)\n","  previous_hash   = blockchain.hash(previous_block)\n","  block           = blockchain.create_block(proof, previous_hash)\n","  response = {'message'       : '¡Enhorabuena, has minado un nuevo bloque!', \n","              'index'         : block['index'],\n","              'timestamp'     : block['timestamp'],\n","              'proof'         : block['proof'],\n","              'previous_hash' : block['previous_hash']}\n","  return jsonify(response), 200\n","\n","@app.route('/get_chain', methods=['GET'])\n","def get_chain():\n","  \"\"\" Obtención de la Blockchain \"\"\"\n","  response = {'chain'   : blockchain.chain, \n","              'length'  : len(blockchain.chain)}\n","  return jsonify(response), 200\n","\n","@app.route('/is_valid', methods = ['GET'])\n","def is_valid():\n","  \"\"\" Comprobación si la Blockchain es válida \"\"\"\n","\n","  is_valid = blockchain.is_chain_valid(blockchain.chain)\n","  if is_valid:\n","      response = {'message' : '¡La cadena de bloques es válida!'}\n","  else:\n","      response = {'message' : '¡La cadena de bloques NO es válida!'}\n","  return jsonify(response), 200  "],"execution_count":10,"outputs":[]},{"cell_type":"code","metadata":{"id":"wGcC8nr5bOKa","colab":{"base_uri":"https://localhost:8080/"},"outputId":"743fec16-89e2-4169-e6d4-590ab07a9732"},"source":["# Ejecución de la app con Google Colab\n","app.run()\n","\n","# Ejecución externa a Google colab\n","# app.run(host = '0.0.0.0', port = 5000)"],"execution_count":null,"outputs":[{"output_type":"stream","name":"stderr","text":[" * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n"]},{"output_type":"stream","name":"stdout","text":[" * Running on http://e56d-35-196-252-107.ngrok.io\n"," * Traffic stats available on http://127.0.0.1:4040\n"]},{"output_type":"stream","name":"stderr","text":["127.0.0.1 - - [28/Nov/2021 12:23:04] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:10] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:11] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:12] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:16] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:17] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:18] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:19] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:20] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:24:53] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:17] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:18] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:19] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:20] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:21] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:21] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:22] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:23] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:23] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:24] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:25] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:26] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:27] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:28] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:29] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:29] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:30] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:31] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:31] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:32] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:28:38] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:29:12] \"\u001b[37mGET /is_valid HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:29:24] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [28/Nov/2021 12:31:19] \"\u001b[37mGET /is_valid HTTP/1.1\u001b[0m\" 200 -\n"]}]}]}

================================================
FILE: BLOQUE 5 - Creación de una Criptomoneda con Python/criptomoneda_5000.ipynb
================================================
{"cells":[{"cell_type":"markdown","metadata":{"id":"aHsnfVt1Yuh2"},"source":["\u003cdiv style=\"width: 100%; clear: both;\"\u003e\n","    \u003cdiv style=\"float: left; width: 20%;\"\u003e\n","       \u003cimg src=\"https://joanamengualcom.files.wordpress.com/2021/11/blockstellart-2.png?w=100\", align=\"left\"\u003e\n","    \u003c/div\u003e\n","\u003c/div\u003e\n","\n","\u003cdiv style=\"float: right; width: 50%;\"\u003e\n","    \u003cp style=\"margin: 0; padding-top: 22px; text-align:right;\"\u003e Construcción de mi Criptomoneda con Python\u003c/p\u003e\n","    \u003cp style=\"margin: 0; text-align:right;\"\u003eFormación en la Tecnología Blockchain\u003c/p\u003e\n","    \u003cp style=\"margin: 0; text-align:right; padding-button: 100px;\"\u003eJoan Amengual\u003c/p\u003e\n","\u003c/div\u003e\n","\n","\u003c/div\u003e\n","\u003cdiv style=\"width: 100%; clear: both;\"\u003e\n","\u003cdiv style=\"width:100%;\"\u003e\u0026nbsp;\u003c/div\u003e"]},{"cell_type":"markdown","metadata":{"id":"FRpA9sywbdVY"},"source":["Librerías necesarias para la creación de una Blockchain con Python:\n","\n","* **datetime**: El módulo datetime proporciona clases para manipular fechas y horas. Si bien la implementación permite operaciones aritméticas con fechas y horas, su principal objetivo es poder extraer campos de forma eficiente para su posterior manipulación o formateo.\n","\n","* **hashlib**: Este módulo implementa una interfaz común a diferentes algoritmos de hash y resúmenes de mensajes seguros. Están incluidos los algoritmos de hash FIPS seguros SHA1, SHA224, SHA226, SHA384 y SHA512 (definidos en FIPS 180-2) además del algoritmo MD5 de RSA (definido en Internet RFC 1321). Los términos «hash seguro» y «resumen de mensaje» son intercambiables. Los algoritmos más antiguos fueron denominados resúmenes de mensajes. El término moderno es hash seguro.\n","\n","* **json**: JSON son las siglas de JavaScript Object Notation. JSON es un formato de datos ligero que se utiliza para el intercambio de datos entre varios lenguajes diferentes. Es fácil de leer para los humanos y fácilmente analizado por las máquinas.\n","\n","* **flask**: Flask es un micro framework web escrito en Python. Se clasifica como un microframework porque no requiere herramientas o librerías particulares. No tiene capa de abstracción de base de datos, validación de formularios, o cualquier otro componente donde las librerías de terceros preexistentes proporcionan funciones comunes. Sin embargo, Flask admite extensiones que pueden añadir funciones a la aplicación como si estuvieran implementadas en el propio Flask. Existen extensiones para mapeadores objeto-relacionales, validación de formularios, manejo de cargas, varias tecnologías de autenticación abierta y varias herramientas relacionadas con el marco común.\n","\n","* **flask-ngrok**: Una forma sencilla de hacer demostraciones de aplicaciones Flask desde tu máquina. Hace que sus aplicaciones Flask que se ejecutan en localhost estén disponibles en Internet a través de la excelente herramienta ngrok.\n","\n","* **requests**: Requests es una biblioteca HTTP para el lenguaje de programación Python. El objetivo del proyecto es hacer que las solicitudes HTTP sean más simples y amigables para los humanos. La versión actual es 2.26.0. Las solicitudes se publican bajo la licencia Apache 2.0.\n","\n","* **uuid**: Este módulo proporciona objetos UUID inmutables (la clase UUID) y las funciones uuid1(), uuid3(), uuid4(), uuid5() para generar UUIDs de las versiones 1, 3, 4 y 5 como se especifica en el RFC 4122.\n","Si lo único que quieres es un ID único, probablemente debas llamar a uuid1() o a uuid4(). Ten en cuenta que uuid1() puede comprometer la privacidad, ya que crea un UUID que contiene la dirección de red del ordenador. uuid4() crea un UUID aleatorio.\n","\n","* **urllib.parse**: Este módulo define una interfaz estándar para dividir las cadenas de localizadores uniformes de recursos (URL) en componentes (esquema de direccionamiento, ubicación en la red, ruta, etc.), para volver a combinar los componentes en una cadena de URL, y para convertir una \"URL relativa\" en una URL absoluta dada una \"URL base\". El módulo ha sido diseñado para ajustarse a la RFC de Internet sobre Localizadores Uniformes de Recursos Relativos. Admite los siguientes esquemas de URL: *file, ftp, gopher, hdl, http, https, imap, mailto, mms, news, nntp, prospero, rsync, rtsp, rtspu, sftp, shttp, sip, sips, snews, svn, svn+ssh, telnet, wais, ws, wss*.\n","\n"]},{"cell_type":"markdown","metadata":{"id":"G12PoXM_cl_G"},"source":["# Instalaciones"]},{"cell_type":"code","execution_count":15,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":3277,"status":"ok","timestamp":1638272943040,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"suKoYcJCZKz4","outputId":"e83d8c8e-ff3b-4a0f-dbcd-9460ef5d9cb3"},"outputs":[{"name":"stdout","output_type":"stream","text":["Requirement already satisfied: flask==1.1.2 in /usr/local/lib/python3.7/dist-packages (1.1.2)\n","Requirement already satisfied: itsdangerous\u003e=0.24 in /usr/local/lib/python3.7/dist-packages (from flask==1.1.2) (1.1.0)\n","Requirement already satisfied: Jinja2\u003e=2.10.1 in /usr/local/lib/python3.7/dist-packages (from flask==1.1.2) (2.11.3)\n","Requirement already satisfied: Werkzeug\u003e=0.15 in /usr/local/lib/python3.7/dist-packages (from flask==1.1.2) (1.0.1)\n","Requirement already satisfied: click\u003e=5.1 in /usr/local/lib/python3.7/dist-packages (from flask==1.1.2) (7.1.2)\n","Requirement already satisfied: MarkupSafe\u003e=0.23 in /usr/local/lib/python3.7/dist-packages (from Jinja2\u003e=2.10.1-\u003eflask==1.1.2) (2.0.1)\n"]}],"source":["!pip install flask==1.1.2"]},{"cell_type":"code","execution_count":16,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":2884,"status":"ok","timestamp":1638272945920,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"kq9_QGleZNfT","outputId":"cb3797a8-48cc-4ac0-a815-0481e08baa4c"},"outputs":[{"name":"stdout","output_type":"stream","text":["Requirement already satisfied: requests==2.25.1 in /usr/local/lib/python3.7/dist-packages (2.25.1)\n","Requirement already satisfied: idna\u003c3,\u003e=2.5 in /usr/local/lib/python3.7/dist-packages (from requests==2.25.1) (2.10)\n","Requirement already satisfied: urllib3\u003c1.27,\u003e=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests==2.25.1) (1.24.3)\n","Requirement already satisfied: certifi\u003e=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests==2.25.1) (2021.10.8)\n","Requirement already satisfied: chardet\u003c5,\u003e=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests==2.25.1) (3.0.4)\n"]}],"source":["!pip install requests==2.25.1"]},{"cell_type":"code","execution_count":17,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":2812,"status":"ok","timestamp":1638272948728,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"24viQDmmZhUS","outputId":"d44bca8b-df34-4be1-e1b7-a53bda0b88d9"},"outputs":[{"name":"stdout","output_type":"stream","text":["Requirement already satisfied: flask-ngrok==0.0.25 in /usr/local/lib/python3.7/dist-packages (0.0.25)\n","Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from flask-ngrok==0.0.25) (2.25.1)\n","Requirement already satisfied: Flask\u003e=0.8 in /usr/local/lib/python3.7/dist-packages (from flask-ngrok==0.0.25) (1.1.2)\n","Requirement already satisfied: itsdangerous\u003e=0.24 in /usr/local/lib/python3.7/dist-packages (from Flask\u003e=0.8-\u003eflask-ngrok==0.0.25) (1.1.0)\n","Requirement already satisfied: Werkzeug\u003e=0.15 in /usr/local/lib/python3.7/dist-packages (from Flask\u003e=0.8-\u003eflask-ngrok==0.0.25) (1.0.1)\n","Requirement already satisfied: Jinja2\u003e=2.10.1 in /usr/local/lib/python3.7/dist-packages (from Flask\u003e=0.8-\u003eflask-ngrok==0.0.25) (2.11.3)\n","Requirement already satisfied: click\u003e=5.1 in /usr/local/lib/python3.7/dist-packages (from Flask\u003e=0.8-\u003eflask-ngrok==0.0.25) (7.1.2)\n","Requirement already satisfied: MarkupSafe\u003e=0.23 in /usr/local/lib/python3.7/dist-packages (from Jinja2\u003e=2.10.1-\u003eFlask\u003e=0.8-\u003eflask-ngrok==0.0.25) (2.0.1)\n","Requirement already satisfied: idna\u003c3,\u003e=2.5 in /usr/local/lib/python3.7/dist-packages (from requests-\u003eflask-ngrok==0.0.25) (2.10)\n","Requirement already satisfied: certifi\u003e=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests-\u003eflask-ngrok==0.0.25) (2021.10.8)\n","Requirement already satisfied: chardet\u003c5,\u003e=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests-\u003eflask-ngrok==0.0.25) (3.0.4)\n","Requirement already satisfied: urllib3\u003c1.27,\u003e=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests-\u003eflask-ngrok==0.0.25) (1.24.3)\n"]}],"source":["!pip install flask-ngrok==0.0.25"]},{"cell_type":"markdown","metadata":{"id":"Ex5WMnYOcoaI"},"source":["# Mi Criptomoneda con Python"]},{"cell_type":"code","execution_count":18,"metadata":{"executionInfo":{"elapsed":5,"status":"ok","timestamp":1638272948729,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"f6PFt3UmZJBH"},"outputs":[],"source":["# Importación de las librerías\n","import datetime\n","import hashlib\n","import json\n","import requests\n","from uuid         import uuid4\n","from flask        import Flask, jsonify, request\n","from urllib.parse import urlparse\n","from flask_ngrok  import run_with_ngrok"]},{"cell_type":"markdown","metadata":{"id":"REfqBNKbcyZK"},"source":["Creación de una clase Blockchain que contenga todos los métodos esenciales, como son los siguientes:\n","\n","* Creación de un nuevo bloque\n","* Obtención del hash de un bloque\n","* Protocolo de concenso Proof of Work (PoW)\n","* Generación del hash de un bloque\n","* Verificación de la validez de la Blockchain\n","* Añadir nueva transacción a la cadena de bloques\n","* Añadir nuevo nodo a la cadena de bloques\n","* Remplazar la Blockchain por la adecuada"]},{"cell_type":"code","execution_count":19,"metadata":{"executionInfo":{"elapsed":550,"status":"ok","timestamp":1638272949275,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"wtjtGb-WY5Vv"},"outputs":[],"source":["class Blockchain:\n","    \n","  def __init__(self):\n","    \"\"\" Constructor de la clase. \"\"\"\n","\n","    self.chain = []\n","    self.transactions = []\n","    self.create_block(proof = 1, previous_hash = '0')\n","    self.nodes = set()\n","      \n","  def create_block(self, proof, previous_hash):\n","    \"\"\" Creación de un nuevo bloque. \n","\n","      Arguments:\n","        - proof: Nounce del bloque actual.\n","        - previous_hash: Hash del bloque previo.\n","\n","      Returns: \n","        - block: Nuevo bloque creado. \n","      \"\"\"\n","\n","    block = { 'index'         : len(self.chain)+1,\n","              'timestamp'     : str(datetime.datetime.now()),\n","              'proof'         : proof,\n","              'previous_hash' : previous_hash,\n","              'transactions'  : self.transactions}\n","    self.transactions = []\n","    self.chain.append(block)\n","    return block\n","\n","  def get_previous_block(self):\n","    \"\"\" Obtención del bloque previo de la Blockchain.\n","    \n","      Returns:\n","        - Obtención del último bloque de la Blockchain. \"\"\"\n","\n","    return self.chain[-1]\n","  \n","  def proof_of_work(self, previous_proof):     \n","    \"\"\" Protocolo de concenso Proof of Work (PoW).\n","    \n","      Arguments:\n","        - previous_proof: Nounce del bloque previo.\n","\n","      Returns:\n","        - new_proof: Devolución del nuevo nounce obtenido con PoW. \"\"\"\n","\n","    new_proof = 1\n","    check_proof = False\n","    while check_proof is False:\n","        hash_operation = hashlib.sha256(str(new_proof**2 - previous_proof**2).encode()).hexdigest()\n","        if hash_operation[:4] == '0000':\n","            check_proof = True\n","        else: \n","            new_proof += 1\n","    return new_proof\n","  \n","  def hash(self, block):\n","    \"\"\" Cálculo del hash de un bloque.\n","    \n","    Arguments:\n","        - block: Identifica a un bloque de la Blockchain.\n","    \n","    Returns:\n","        - hash_block: Devuelve el hash del bloque \"\"\"\n","\n","    encoded_block = json.dumps(block, sort_keys = True).encode()\n","    hash_block = hashlib.sha256(encoded_block).hexdigest()\n","    return hash_block\n","  \n","  def is_chain_valid(self, chain):\n","    \"\"\" Determina si la Blockchain es válida. \n","    \n","    Arguments:\n","        - chain: Cadena de bloques que contiene toda la \n","                  información de las transacciones.\n","    \n","    Returns:\n","        - True/False: Devuelve un booleano en función de la validez de la \n","                      Blockchain. (True = Válida, False = Inválida) \"\"\"\n","                      \n","    previous_block = chain[0]\n","    block_index = 1\n","    while block_index \u003c len(chain):\n","        block = chain[block_index]\n","        if block['previous_hash'] != self.hash(previous_block):\n","            return False\n","        previous_proof = previous_block['proof']\n","        proof = block['proof']\n","        hash_operation = hashlib.sha256(str(proof**2 - previous_proof**2).encode()).hexdigest()\n","        if hash_operation[:4] != '0000':\n","            return False\n","        previous_block = block\n","        block_index += 1\n","    return True\n","  \n","  def add_transaction(self, sender, receiver, amount):\n","    \"\"\" Realización de una transacción.\n","    \n","    Arguments:\n","        - sender: Persona que hace la transacción\n","        - receiver: Persona que recibe la transacción\n","        - amount: Cantidad de criptomonedas enviadas\n","\n","    Returns: \n","        - Devolución del índice superior al último bloque\n","    \"\"\"\n","\n","    self.transactions.append({'sender'  : sender,\n","                              'receiver': receiver, \n","                              'amount'  : amount})\n","    previous_block = self.get_previous_block()\n","    return previous_block['index'] + 1\n","\n","  def add_node(self, address):\n","    \"\"\" Nuevo nodo en la Blockchain.\n","    \n","      Arguments:\n","        - address: Dirección del nuevo nodo\n","    \"\"\"\n","\n","    parsed_url = urlparse(address)\n","    self.nodes.add(parsed_url.netloc)\n","  \n","  def replace_chain(self):\n","    \"\"\" Remplazo de la cadena por la cadena más larga, \n","    siempre y cuando sea válida. \"\"\"\n","    \n","    network = self.nodes\n","    longest_chain = None\n","    max_length = len(self.chain)\n","    for node in network:\n","        response = requests.get(f'http://{node}/get_chain')\n","        if response.status_code == 200:\n","            length = response.json()['length']\n","            chain = response.json()['chain']\n","            if length \u003e max_length and self.is_chain_valid(chain):\n","                max_length = length\n","                longest_chain = chain\n","    if longest_chain: \n","        self.chain = longest_chain\n","        return True\n","    return False"]},{"cell_type":"code","execution_count":20,"metadata":{"executionInfo":{"elapsed":7,"status":"ok","timestamp":1638272949275,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"oqozjmL-Zelo"},"outputs":[],"source":["# Minado de un Bloque de la Cadena\n","\n","# Crear una aplicación web\n","app = Flask(__name__)\n","run_with_ngrok(app)  \n","\n","# Si se obtiene un error 500, actualizar flask, reiniciar spyder y ejecutar la siguiente línea\n","app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False\n","\n","# Crear la dirección del nodo en el puerto 5000\n","node_address = str(uuid4()).replace('-', '')\n","\n","# Crear una Blockchain\n","blockchain = Blockchain()\n","\n","\n","@app.route('/mine_block', methods=['GET'])\n","def mine_block():\n","  \"\"\" Minado de un nuevo bloque \"\"\" \n","\n","  previous_block = blockchain.get_previous_block()\n","  previous_proof = previous_block['proof']\n","  proof = blockchain.proof_of_work(previous_proof)\n","  previous_hash = blockchain.hash(previous_block)\n","  blockchain.add_transaction(sender = node_address, receiver = \"Joan Amengual\", amount = 10)\n","  block = blockchain.create_block(proof, previous_hash)\n","  response = {'message'       : '¡Enhorabuena, nuevo bloque minado!', \n","              'index'         : block['index'],\n","              'timestamp'     : block['timestamp'],\n","              'proof'         : block['proof'],\n","              'previous_hash' : block['previous_hash'],\n","              'transactions'  : block['transactions']}\n","  return jsonify(response), 200\n","\n","@app.route('/get_chain', methods=['GET'])\n","def get_chain():\n","  \"\"\" Obtención de la cadena de bloques al completo \"\"\"\n","\n","  response = {'chain'   : blockchain.chain, \n","              'length'  : len(blockchain.chain)}\n","  return jsonify(response), 200\n","\n","@app.route('/is_valid', methods = ['GET'])\n","def is_valid():\n","  \"\"\" Comprobación de si la cadena de bloques es válida \"\"\"\n","\n","  is_valid = blockchain.is_chain_valid(blockchain.chain)\n","  if is_valid:\n","      response = {'message' : 'Todo correcto. La cadena de bloques es válida.'}\n","  else:\n","      response = {'message' : 'UPS. La cadena de bloques NO es válida.'}\n","  return jsonify(response), 200  \n","\n","@app.route('/add_transaction', methods = ['POST'])\n","def add_transaction():\n","  \"\"\" Añadir una nueva transacción a la cadena de bloques \"\"\"\n","\n","  json = request.get_json()\n","  transaction_keys = ['sender', 'receiver', 'amount']\n","  if not all(key in json for key in transaction_keys):\n","      return 'Faltan algunos elementos de la transacción', 400\n","  index = blockchain.add_transaction(json['sender'], json['receiver'], json['amount'])\n","  response = {'message': f'La transacción será añadida al bloque {index}'}\n","  return jsonify(response), 201\n","    \n","# Descentralización de la Cadena de Bloques\n","\n","# Conectar nuevos nodos\n","@app.route('/connect_node', methods = ['POST'])\n","def connect_node():\n","  json = request.get_json()\n","  nodes = json.get('nodes')\n","  if nodes is None: \n","      return 'No hay nodos para añadir', 400\n","  for node in nodes:\n","      blockchain.add_node(node)\n","  response = {'message'     : 'Todos los nodos han sido conectados. La Blockchain de JoanCoins contiene ahora los nodos siguientes: ',\n","              'total_nodes' : list(blockchain.nodes)}\n","  return jsonify(response), 201\n","\n","@app.route('/replace_chain', methods = ['GET'])\n","def replace_chain():\n","  \"\"\" Reemplazar la cadena por la más larga (si es necesario) \"\"\"\n","\n","  is_chain_replaced = blockchain.replace_chain()\n","  if is_chain_replaced:\n","      response = {'message' : 'Los nodos tenían diferentes cadenas, se ha remplazado por la Blockchain más larga.',\n","                  'new_chain': blockchain.chain}\n","  else:\n","      response = {'message'       : 'Todo correcto. La Blockchain en todos los nodos ya es la más larga.',\n","                  'actual_chain'  : blockchain.chain}\n","  return jsonify(response), 200  "]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"background_save":true,"base_uri":"https://localhost:8080/"},"id":"ugVnFGyfa-ND"},"outputs":[{"name":"stdout","output_type":"stream","text":[" * Serving Flask app \"__main__\" (lazy loading)\n"," * Environment: production\n","\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n","\u001b[2m   Use a production WSGI server instead.\u001b[0m\n"," * Debug mode: off\n"]},{"name":"stderr","output_type":"stream","text":[" * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n"]},{"name":"stdout","output_type":"stream","text":[" * Running on http://b3ef-35-227-158-117.ngrok.io\n"," * Traffic stats available on http://127.0.0.1:4040\n"]},{"name":"stderr","output_type":"stream","text":["127.0.0.1 - - [30/Nov/2021 11:50:42] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:52:23] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:53:08] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:53:40] \"\u001b[37mGET /is_valid HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:54:36] \"\u001b[37mPOST /add_transaction HTTP/1.1\u001b[0m\" 201 -\n","127.0.0.1 - - [30/Nov/2021 11:54:43] \"\u001b[31m\u001b[1mPOST /get_chain HTTP/1.1\u001b[0m\" 405 -\n","127.0.0.1 - - [30/Nov/2021 11:54:50] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:55:10] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:55:24] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:56:55] \"\u001b[37mPOST /connect_node HTTP/1.1\u001b[0m\" 201 -\n","127.0.0.1 - - [30/Nov/2021 11:58:07] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:58:16] \"\u001b[37mGET /replace_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:01:38] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:01:53] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:02:24] \"\u001b[37mGET /replace_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:02:39] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n"]}],"source":["# Ejecución de la app con Google Colab\n","app.run()\n","\n","# Ejecución externa a Google colab\n","#app.run(host = '0.0.0.0', port = 5000)"]}],"metadata":{"colab":{"authorship_tag":"ABX9TyORh9il2u2BExXCSoIo0jm/","collapsed_sections":[],"name":"criptomoneda_5000.ipynb","version":""},"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0}

================================================
FILE: BLOQUE 5 - Creación de una Criptomoneda con Python/criptomoneda_5001.ipynb
================================================
{"cells":[{"cell_type":"markdown","metadata":{"id":"aHsnfVt1Yuh2"},"source":["\u003cdiv style=\"width: 100%; clear: both;\"\u003e\n","    \u003cdiv style=\"float: left; width: 20%;\"\u003e\n","       \u003cimg src=\"https://joanamengualcom.files.wordpress.com/2021/11/blockstellart-2.png?w=100\", align=\"left\"\u003e\n","    \u003c/div\u003e\n","\u003c/div\u003e\n","\n","\u003cdiv style=\"float: right; width: 50%;\"\u003e\n","    \u003cp style=\"margin: 0; padding-top: 22px; text-align:right;\"\u003e Construcción de mi Criptomoneda con Python\u003c/p\u003e\n","    \u003cp style=\"margin: 0; text-align:right;\"\u003eFormación en la Tecnología Blockchain\u003c/p\u003e\n","    \u003cp style=\"margin: 0; text-align:right; padding-button: 100px;\"\u003eJoan Amengual\u003c/p\u003e\n","\u003c/div\u003e\n","\n","\u003c/div\u003e\n","\u003cdiv style=\"width: 100%; clear: both;\"\u003e\n","\u003cdiv style=\"width:100%;\"\u003e\u0026nbsp;\u003c/div\u003e"]},{"cell_type":"markdown","metadata":{"id":"FRpA9sywbdVY"},"source":["Librerías necesarias para la creación de una Blockchain con Python:\n","\n","* **datetime**: El módulo datetime proporciona clases para manipular fechas y horas. Si bien la implementación permite operaciones aritméticas con fechas y horas, su principal objetivo es poder extraer campos de forma eficiente para su posterior manipulación o formateo.\n","\n","* **hashlib**: Este módulo implementa una interfaz común a diferentes algoritmos de hash y resúmenes de mensajes seguros. Están incluidos los algoritmos de hash FIPS seguros SHA1, SHA224, SHA226, SHA384 y SHA512 (definidos en FIPS 180-2) además del algoritmo MD5 de RSA (definido en Internet RFC 1321). Los términos «hash seguro» y «resumen de mensaje» son intercambiables. Los algoritmos más antiguos fueron denominados resúmenes de mensajes. El término moderno es hash seguro.\n","\n","* **json**: JSON son las siglas de JavaScript Object Notation. JSON es un formato de datos ligero que se utiliza para el intercambio de datos entre varios lenguajes diferentes. Es fácil de leer para los humanos y fácilmente analizado por las máquinas.\n","\n","* **flask**: Flask es un micro framework web escrito en Python. Se clasifica como un microframework porque no requiere herramientas o librerías particulares. No tiene capa de abstracción de base de datos, validación de formularios, o cualquier otro componente donde las librerías de terceros preexistentes proporcionan funciones comunes. Sin embargo, Flask admite extensiones que pueden añadir funciones a la aplicación como si estuvieran implementadas en el propio Flask. Existen extensiones para mapeadores objeto-relacionales, validación de formularios, manejo de cargas, varias tecnologías de autenticación abierta y varias herramientas relacionadas con el marco común.\n","\n","* **flask-ngrok**: Una forma sencilla de hacer demostraciones de aplicaciones Flask desde tu máquina. Hace que sus aplicaciones Flask que se ejecutan en localhost estén disponibles en Internet a través de la excelente herramienta ngrok.\n","\n","* **requests**: Requests es una biblioteca HTTP para el lenguaje de programación Python. El objetivo del proyecto es hacer que las solicitudes HTTP sean más simples y amigables para los humanos. La versión actual es 2.26.0. Las solicitudes se publican bajo la licencia Apache 2.0.\n","\n","* **uuid**: Este módulo proporciona objetos UUID inmutables (la clase UUID) y las funciones uuid1(), uuid3(), uuid4(), uuid5() para generar UUIDs de las versiones 1, 3, 4 y 5 como se especifica en el RFC 4122.\n","Si lo único que quieres es un ID único, probablemente debas llamar a uuid1() o a uuid4(). Ten en cuenta que uuid1() puede comprometer la privacidad, ya que crea un UUID que contiene la dirección de red del ordenador. uuid4() crea un UUID aleatorio.\n","\n","* **urllib.parse**: Este módulo define una interfaz estándar para dividir las cadenas de localizadores uniformes de recursos (URL) en componentes (esquema de direccionamiento, ubicación en la red, ruta, etc.), para volver a combinar los componentes en una cadena de URL, y para convertir una \"URL relativa\" en una URL absoluta dada una \"URL base\". El módulo ha sido diseñado para ajustarse a la RFC de Internet sobre Localizadores Uniformes de Recursos Relativos. Admite los siguientes esquemas de URL: *file, ftp, gopher, hdl, http, https, imap, mailto, mms, news, nntp, prospero, rsync, rtsp, rtspu, sftp, shttp, sip, sips, snews, svn, svn+ssh, telnet, wais, ws, wss*.\n","\n"]},{"cell_type":"markdown","metadata":{"id":"G12PoXM_cl_G"},"source":["# Instalaciones"]},{"cell_type":"code","execution_count":1,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":5977,"status":"ok","timestamp":1638272957844,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"suKoYcJCZKz4","outputId":"c461b583-2632-4bb9-89ac-fce673733caa"},"outputs":[{"name":"stdout","output_type":"stream","text":["Collecting flask==1.1.2\n","  Downloading Flask-1.1.2-py2.py3-none-any.whl (94 kB)\n","\u001b[K     |████████████████████████████████| 94 kB 926 kB/s \n","\u001b[?25hRequirement already satisfied: click\u003e=5.1 in /usr/local/lib/python3.7/dist-packages (from flask==1.1.2) (7.1.2)\n","Requirement already satisfied: Jinja2\u003e=2.10.1 in /usr/local/lib/python3.7/dist-packages (from flask==1.1.2) (2.11.3)\n","Requirement already satisfied: itsdangerous\u003e=0.24 in /usr/local/lib/python3.7/dist-packages (from flask==1.1.2) (1.1.0)\n","Requirement already satisfied: Werkzeug\u003e=0.15 in /usr/local/lib/python3.7/dist-packages (from flask==1.1.2) (1.0.1)\n","Requirement already satisfied: MarkupSafe\u003e=0.23 in /usr/local/lib/python3.7/dist-packages (from Jinja2\u003e=2.10.1-\u003eflask==1.1.2) (2.0.1)\n","Installing collected packages: flask\n","  Attempting uninstall: flask\n","    Found existing installation: Flask 1.1.4\n","    Uninstalling Flask-1.1.4:\n","      Successfully uninstalled Flask-1.1.4\n","Successfully installed flask-1.1.2\n"]}],"source":["!pip install flask==1.1.2"]},{"cell_type":"code","execution_count":2,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":3987,"status":"ok","timestamp":1638272961826,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"kq9_QGleZNfT","outputId":"53c6e0f6-634b-4ce2-9abb-b60833849d2a"},"outputs":[{"name":"stdout","output_type":"stream","text":["Collecting requests==2.25.1\n","  Downloading requests-2.25.1-py2.py3-none-any.whl (61 kB)\n","\u001b[?25l\r\u001b[K     |█████▍                          | 10 kB 18.3 MB/s eta 0:00:01\r\u001b[K     |██████████▊                     | 20 kB 14.0 MB/s eta 0:00:01\r\u001b[K     |████████████████                | 30 kB 9.7 MB/s eta 0:00:01\r\u001b[K     |█████████████████████▍          | 40 kB 8.7 MB/s eta 0:00:01\r\u001b[K     |██████████████████████████▊     | 51 kB 4.3 MB/s eta 0:00:01\r\u001b[K     |████████████████████████████████| 61 kB 3.1 MB/s \n","\u001b[?25hRequirement already satisfied: chardet\u003c5,\u003e=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests==2.25.1) (3.0.4)\n","Requirement already satisfied: idna\u003c3,\u003e=2.5 in /usr/local/lib/python3.7/dist-packages (from requests==2.25.1) (2.10)\n","Requirement already satisfied: urllib3\u003c1.27,\u003e=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests==2.25.1) (1.24.3)\n","Requirement already satisfied: certifi\u003e=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests==2.25.1) (2021.10.8)\n","Installing collected packages: requests\n","  Attempting uninstall: requests\n","    Found existing installation: requests 2.23.0\n","    Uninstalling requests-2.23.0:\n","      Successfully uninstalled requests-2.23.0\n","\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n","google-colab 1.0.0 requires requests~=2.23.0, but you have requests 2.25.1 which is incompatible.\n","datascience 0.10.6 requires folium==0.2.1, but you have folium 0.8.3 which is incompatible.\u001b[0m\n","Successfully installed requests-2.25.1\n"]}],"source":["!pip install requests==2.25.1"]},{"cell_type":"code","execution_count":3,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":3711,"status":"ok","timestamp":1638272965533,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"24viQDmmZhUS","outputId":"e2cf6f74-99c0-4dd0-aac8-6b15cea516ef"},"outputs":[{"name":"stdout","output_type":"stream","text":["Collecting flask-ngrok==0.0.25\n","  Downloading flask_ngrok-0.0.25-py3-none-any.whl (3.1 kB)\n","Requirement already satisfied: Flask\u003e=0.8 in /usr/local/lib/python3.7/dist-packages (from flask-ngrok==0.0.25) (1.1.2)\n","Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from flask-ngrok==0.0.25) (2.25.1)\n","Requirement already satisfied: click\u003e=5.1 in /usr/local/lib/python3.7/dist-packages (from Flask\u003e=0.8-\u003eflask-ngrok==0.0.25) (7.1.2)\n","Requirement already satisfied: Jinja2\u003e=2.10.1 in /usr/local/lib/python3.7/dist-packages (from Flask\u003e=0.8-\u003eflask-ngrok==0.0.25) (2.11.3)\n","Requirement already satisfied: Werkzeug\u003e=0.15 in /usr/local/lib/python3.7/dist-packages (from Flask\u003e=0.8-\u003eflask-ngrok==0.0.25) (1.0.1)\n","Requirement already satisfied: itsdangerous\u003e=0.24 in /usr/local/lib/python3.7/dist-packages (from Flask\u003e=0.8-\u003eflask-ngrok==0.0.25) (1.1.0)\n","Requirement already satisfied: MarkupSafe\u003e=0.23 in /usr/local/lib/python3.7/dist-packages (from Jinja2\u003e=2.10.1-\u003eFlask\u003e=0.8-\u003eflask-ngrok==0.0.25) (2.0.1)\n","Requirement already satisfied: idna\u003c3,\u003e=2.5 in /usr/local/lib/python3.7/dist-packages (from requests-\u003eflask-ngrok==0.0.25) (2.10)\n","Requirement already satisfied: urllib3\u003c1.27,\u003e=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests-\u003eflask-ngrok==0.0.25) (1.24.3)\n","Requirement already satisfied: certifi\u003e=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests-\u003eflask-ngrok==0.0.25) (2021.10.8)\n","Requirement already satisfied: chardet\u003c5,\u003e=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests-\u003eflask-ngrok==0.0.25) (3.0.4)\n","Installing collected packages: flask-ngrok\n","Successfully installed flask-ngrok-0.0.25\n"]}],"source":["!pip install flask-ngrok==0.0.25"]},{"cell_type":"markdown","metadata":{"id":"Ex5WMnYOcoaI"},"source":["# Mi Criptomoneda con Python"]},{"cell_type":"code","execution_count":4,"metadata":{"executionInfo":{"elapsed":9,"status":"ok","timestamp":1638272965534,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"f6PFt3UmZJBH"},"outputs":[],"source":["# Importación de las librerías\n","import datetime\n","import hashlib\n","import json\n","import requests\n","from uuid         import uuid4\n","from flask        import Flask, jsonify, request\n","from urllib.parse import urlparse\n","from flask_ngrok  import run_with_ngrok"]},{"cell_type":"markdown","metadata":{"id":"REfqBNKbcyZK"},"source":["Creación de una clase Blockchain que contenga todos los métodos esenciales, como son los siguientes:\n","\n","* Creación de un nuevo bloque\n","* Obtención del hash de un bloque\n","* Protocolo de concenso Proof of Work (PoW)\n","* Generación del hash de un bloque\n","* Verificación de la validez de la Blockchain\n","* Añadir nueva transacción a la cadena de bloques\n","* Añadir nuevo nodo a la cadena de bloques\n","* Remplazar la Blockchain por la adecuada"]},{"cell_type":"code","execution_count":5,"metadata":{"executionInfo":{"elapsed":7,"status":"ok","timestamp":1638272965534,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"wtjtGb-WY5Vv"},"outputs":[],"source":["class Blockchain:\n","    \n","  def __init__(self):\n","    \"\"\" Constructor de la clase. \"\"\"\n","\n","    self.chain = []\n","    self.transactions = []\n","    self.create_block(proof = 1, previous_hash = '0')\n","    self.nodes = set()\n","      \n","  def create_block(self, proof, previous_hash):\n","    \"\"\" Creación de un nuevo bloque. \n","\n","      Arguments:\n","        - proof: Nounce del bloque actual.\n","        - previous_hash: Hash del bloque previo.\n","\n","      Returns: \n","        - block: Nuevo bloque creado. \n","      \"\"\"\n","\n","    block = { 'index'         : len(self.chain)+1,\n","              'timestamp'     : str(datetime.datetime.now()),\n","              'proof'         : proof,\n","              'previous_hash' : previous_hash,\n","              'transactions'  : self.transactions}\n","    self.transactions = []\n","    self.chain.append(block)\n","    return block\n","\n","  def get_previous_block(self):\n","    \"\"\" Obtención del bloque previo de la Blockchain.\n","    \n","      Returns:\n","        - Obtención del último bloque de la Blockchain. \"\"\"\n","\n","    return self.chain[-1]\n","  \n","  def proof_of_work(self, previous_proof):     \n","    \"\"\" Protocolo de concenso Proof of Work (PoW).\n","    \n","      Arguments:\n","        - previous_proof: Nounce del bloque previo.\n","\n","      Returns:\n","        - new_proof: Devolución del nuevo nounce obtenido con PoW. \"\"\"\n","\n","    new_proof = 1\n","    check_proof = False\n","    while check_proof is False:\n","        hash_operation = hashlib.sha256(str(new_proof**2 - previous_proof**2).encode()).hexdigest()\n","        if hash_operation[:4] == '0000':\n","            check_proof = True\n","        else: \n","            new_proof += 1\n","    return new_proof\n","  \n","  def hash(self, block):\n","    \"\"\" Cálculo del hash de un bloque.\n","    \n","    Arguments:\n","        - block: Identifica a un bloque de la Blockchain.\n","    \n","    Returns:\n","        - hash_block: Devuelve el hash del bloque \"\"\"\n","\n","    encoded_block = json.dumps(block, sort_keys = True).encode()\n","    hash_block = hashlib.sha256(encoded_block).hexdigest()\n","    return hash_block\n","  \n","  def is_chain_valid(self, chain):\n","    \"\"\" Determina si la Blockchain es válida. \n","    \n","    Arguments:\n","        - chain: Cadena de bloques que contiene toda la \n","                  información de las transacciones.\n","    \n","    Returns:\n","        - True/False: Devuelve un booleano en función de la validez de la \n","                      Blockchain. (True = Válida, False = Inválida) \"\"\"\n","                      \n","    previous_block = chain[0]\n","    block_index = 1\n","    while block_index \u003c len(chain):\n","        block = chain[block_index]\n","        if block['previous_hash'] != self.hash(previous_block):\n","            return False\n","        previous_proof = previous_block['proof']\n","        proof = block['proof']\n","        hash_operation = hashlib.sha256(str(proof**2 - previous_proof**2).encode()).hexdigest()\n","        if hash_operation[:4] != '0000':\n","            return False\n","        previous_block = block\n","        block_index += 1\n","    return True\n","  \n","  def add_transaction(self, sender, receiver, amount):\n","    \"\"\" Realización de una transacción.\n","    \n","    Arguments:\n","        - sender: Persona que hace la transacción\n","        - receiver: Persona que recibe la transacción\n","        - amount: Cantidad de criptomonedas enviadas\n","\n","    Returns: \n","        - Devolución del índice superior al último bloque\n","    \"\"\"\n","\n","    self.transactions.append({'sender'  : sender,\n","                              'receiver': receiver, \n","                              'amount'  : amount})\n","    previous_block = self.get_previous_block()\n","    return previous_block['index'] + 1\n","\n","  def add_node(self, address):\n","    \"\"\" Nuevo nodo en la Blockchain.\n","    \n","      Arguments:\n","        - address: Dirección del nuevo nodo\n","    \"\"\"\n","\n","    parsed_url = urlparse(address)\n","    self.nodes.add(parsed_url.netloc)\n","  \n","  def replace_chain(self):\n","    \"\"\" Remplazo de la cadena por la cadena más larga, \n","    siempre y cuando sea válida. \"\"\"\n","    \n","    network = self.nodes\n","    longest_chain = None\n","    max_length = len(self.chain)\n","    for node in network:\n","        response = requests.get(f'http://{node}/get_chain')\n","        if response.status_code == 200:\n","            length = response.json()['length']\n","            chain = response.json()['chain']\n","            if length \u003e max_length and self.is_chain_valid(chain):\n","                max_length = length\n","                longest_chain = chain\n","    if longest_chain: \n","        self.chain = longest_chain\n","        return True\n","    return False"]},{"cell_type":"code","execution_count":6,"metadata":{"executionInfo":{"elapsed":545,"status":"ok","timestamp":1638272966073,"user":{"displayName":"Joan Amengual","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjmlyFZpl5jEBtPejqXWqbr2r_E-kHJVzCG76V-3PI=s64","userId":"00234468366958344467"},"user_tz":-60},"id":"oqozjmL-Zelo"},"outputs":[],"source":["# Minado de un Bloque de la Cadena\n","\n","# Crear una aplicación web\n","app = Flask(__name__)\n","run_with_ngrok(app)  \n","\n","# Si se obtiene un error 500, actualizar flask, reiniciar spyder y ejecutar la siguiente línea\n","app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False\n","\n","# Crear la dirección del nodo en el puerto 5000\n","node_address = str(uuid4()).replace('-', '')\n","\n","# Crear una Blockchain\n","blockchain = Blockchain()\n","\n","\n","@app.route('/mine_block', methods=['GET'])\n","def mine_block():\n","  \"\"\" Minado de un nuevo bloque \"\"\" \n","\n","  previous_block = blockchain.get_previous_block()\n","  previous_proof = previous_block['proof']\n","  proof = blockchain.proof_of_work(previous_proof)\n","  previous_hash = blockchain.hash(previous_block)\n","  blockchain.add_transaction(sender = node_address, receiver = \"Alberto Pousada\", amount = 10)\n","  block = blockchain.create_block(proof, previous_hash)\n","  response = {'message'       : '¡Enhorabuena, nuevo bloque minado!', \n","              'index'         : block['index'],\n","              'timestamp'     : block['timestamp'],\n","              'proof'         : block['proof'],\n","              'previous_hash' : block['previous_hash'],\n","              'transactions'  : block['transactions']}\n","  return jsonify(response), 200\n","\n","@app.route('/get_chain', methods=['GET'])\n","def get_chain():\n","  \"\"\" Obtención de la cadena de bloques al completo \"\"\"\n","\n","  response = {'chain'   : blockchain.chain, \n","              'length'  : len(blockchain.chain)}\n","  return jsonify(response), 200\n","\n","@app.route('/is_valid', methods = ['GET'])\n","def is_valid():\n","  \"\"\" Comprobación de si la cadena de bloques es válida \"\"\"\n","\n","  is_valid = blockchain.is_chain_valid(blockchain.chain)\n","  if is_valid:\n","      response = {'message' : 'Todo correcto. La cadena de bloques es válida.'}\n","  else:\n","      response = {'message' : 'UPS. La cadena de bloques NO es válida.'}\n","  return jsonify(response), 200  \n","\n","@app.route('/add_transaction', methods = ['POST'])\n","def add_transaction():\n","  \"\"\" Añadir una nueva transacción a la cadena de bloques \"\"\"\n","\n","  json = request.get_json()\n","  transaction_keys = ['sender', 'receiver', 'amount']\n","  if not all(key in json for key in transaction_keys):\n","      return 'Faltan algunos elementos de la transacción', 400\n","  index = blockchain.add_transaction(json['sender'], json['receiver'], json['amount'])\n","  response = {'message': f'La transacción será añadida al bloque {index}'}\n","  return jsonify(response), 201\n","    \n","# Descentralización de la Cadena de Bloques\n","\n","# Conectar nuevos nodos\n","@app.route('/connect_node', methods = ['POST'])\n","def connect_node():\n","  json = request.get_json()\n","  nodes = json.get('nodes')\n","  if nodes is None: \n","      return 'No hay nodos para añadir', 400\n","  for node in nodes:\n","      blockchain.add_node(node)\n","  response = {'message'     : 'Todos los nodos han sido conectados. La Blockchain de JoanCoins contiene ahora los nodos siguientes: ',\n","              'total_nodes' : list(blockchain.nodes)}\n","  return jsonify(response), 201\n","\n","@app.route('/replace_chain', methods = ['GET'])\n","def replace_chain():\n","  \"\"\" Reemplazar la cadena por la más larga (si es necesario) \"\"\"\n","\n","  is_chain_replaced = blockchain.replace_chain()\n","  if is_chain_replaced:\n","      response = {'message' : 'Los nodos tenían diferentes cadenas, se ha remplazado por la Blockchain más larga.',\n","                  'new_chain': blockchain.chain}\n","  else:\n","      response = {'message'       : 'Todo correcto. La Blockchain en todos los nodos ya es la más larga.',\n","                  'actual_chain'  : blockchain.chain}\n","  return jsonify(response), 200  "]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"background_save":true,"base_uri":"https://localhost:8080/"},"id":"ugVnFGyfa-ND"},"outputs":[{"name":"stdout","output_type":"stream","text":[" * Serving Flask app \"__main__\" (lazy loading)\n"," * Environment: production\n","\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n","\u001b[2m   Use a production WSGI server instead.\u001b[0m\n"," * Debug mode: off\n"]},{"name":"stderr","output_type":"stream","text":[" * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)\n"]},{"name":"stdout","output_type":"stream","text":[" * Running on http://c467-104-199-135-247.ngrok.io\n"," * Traffic stats available on http://127.0.0.1:4040\n"]},{"name":"stderr","output_type":"stream","text":["127.0.0.1 - - [30/Nov/2021 11:51:12] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:53:17] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:56:05] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:57:17] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:57:38] \"\u001b[37mGET /replace_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 11:58:16] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:00:56] \"\u001b[37mPOST /connect_node HTTP/1.1\u001b[0m\" 201 -\n","127.0.0.1 - - [30/Nov/2021 12:01:38] \"\u001b[37mGET /replace_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:01:54] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:02:09] \"\u001b[37mGET /mine_block HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:02:23] \"\u001b[37mGET /get_chain HTTP/1.1\u001b[0m\" 200 -\n","127.0.0.1 - - [30/Nov/2021 12:02:39] \"\u001b[37mGET /replace_chain HTTP/1.1\u001b[0m\" 200 -\n"]}],"source":["# Ejecución de la app con Google Colab\n","app.run()\n","\n","# Ejecución externa a Google colab\n","#app.run(host = '0.0.0.0', port = 5001)"]}],"metadata":{"colab":{"authorship_tag":"ABX9TyMcOnOrLMozXIfH0N+7qgt6","collapsed_sections":[],"name":"criptomoneda_5001.ipynb","version":""},"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0}

================================================
FILE: BLOQUE 5 - Creación de una Criptomoneda con Python/criptomoneda_5002.ipynb
================================================
{"cells":[{"cell_type":"markdown","metadata":{"id":"aHsnfVt1Yuh2"},"source":["\u003cdiv style=\"width: 100%; clear: both;\"\u003e\n","    \u003cdiv style=\"float: left; width: 20%;\"\u003e\n","       \u003cimg src=\"https://joanamengualcom.files.wordpress.com/2021/11/blockstellart-2.png?w=100\", align=\"left\"\u003e\n","    \u003c/div\u003e\n","\u003c/div\u003e\n","\n","\u003cdiv style=\"float: right; width: 50%;\"\u003e\n","    \u003cp style=\"margin: 0; padding-top: 22px; text-align:right;\"\u003e Construcción de mi Criptomoneda con Python\u003c/p\u003e\n","    \u003cp style=\"margin: 0; text-align:right;\"\u003eFormación en la Tecnología Blockchain\u003c/p\u003e\n","    \u003cp style=\"margin: 0; text-align:right; padding-button: 100px;\"\u003eJoan Amengual\u003c/p\u003e\n","\u003c/div\u003e\n","\n","\u003c/div\u003e\n","\u003cdiv style=\"width: 100%; clear: both;\"\u003e\n","\u003cdiv style=\"width:100%;\"\u003e\u0026nbsp;\u003c/div\u003e"]},{"cell_type":"markdown","metadata":{"id":"FRpA9sywbdVY"},"source":["Librerías necesarias para la creaci
Download .txt
gitextract_nsm2lemb/

├── .gitignore
├── BLOQUE 1 - Conceptos básicos de Solidity/
│   ├── Tema 1 - Primeros pasos/
│   │   ├── ERC20.sol
│   │   ├── SafeMath.sol
│   │   └── conceptos_basicos.sol
│   ├── Tema 10 - Fábrica de Smart Contracts/
│   │   └── factory.sol
│   ├── Tema 2 - Propiedades transacciones y bloques/
│   │   ├── funciones_globales.sol
│   │   └── keccak256.sol
│   ├── Tema 3 - Tipos de variables y operadores/
│   │   ├── Modificadores.sol
│   │   ├── Operadores.sol
│   │   ├── casteo_variables.sol
│   │   ├── comparar_strings.sol
│   │   ├── enum.sol
│   │   ├── mas_variables.sol
│   │   ├── unidades_tiempo.sol
│   │   └── variables_enteras.sol
│   ├── Tema 4 - Estructuras de datos/
│   │   ├── Estructuras.sol
│   │   ├── arrays.sol
│   │   └── mappings.sol
│   ├── Tema 5 - Funciones/
│   │   ├── causas_beneficas.sol
│   │   ├── eventos.sol
│   │   ├── funciones.sol
│   │   ├── modificadores.sol
│   │   └── returns.sol
│   ├── Tema 6 - Bucles y condicionales/
│   │   ├── bucle_for.sol
│   │   ├── bucle_while.sol
│   │   └── sentencia_if.sol
│   ├── Tema 7 - Interactuando con otros Smart Contracts/
│   │   ├── Banco.sol
│   │   ├── Cliente.sol
│   │   ├── herencia.sol
│   │   └── librerias.sol
│   ├── Tema 8 - Funciones avanzadas/
│   │   ├── internal_external.sol
│   │   ├── modifier.sol
│   │   └── require.sol
│   └── Tema 9 - SafeMath/
│       ├── SafeMath.sol
│       ├── SafeMath_comentada.sol
│       └── ejemplo_uso.sol
├── BLOQUE 2 - Proyectos reales con Smart Contracts/
│   ├── Creación y uso de un Token ERC-20/
│   │   ├── ERC20.sol
│   │   └── SafeMath.sol
│   ├── DISNEY/
│   │   ├── ERC20.sol
│   │   ├── SafeMath.sol
│   │   └── disney.sol
│   ├── Evaluaciones universitarias con un Smart Contract/
│   │   └── notas.sol
│   ├── LOTERIA/
│   │   ├── ERC20.sol
│   │   ├── SafeMath.sol
│   │   └── loteria.sol
│   ├── OMS/
│   │   └── oms.sol
│   └── VOTACION/
│       ├── votacion.sol
│       └── votacion_tarea.sol
├── BLOQUE 3 - Proyecto final de curso/
│   └── PROYECTO FINAL - Servicio de telemedicina/
│       ├── ERC20.sol
│       ├── MedicalInsurance.sol
│       ├── OperacionesBasicas.sol
│       └── SafeMath.sol
├── BLOQUE 4 - Creación de una Blockchain con Python/
│   └── blockchain.ipynb
├── BLOQUE 5 - Creación de una Criptomoneda con Python/
│   ├── criptomoneda_5000.ipynb
│   ├── criptomoneda_5001.ipynb
│   ├── criptomoneda_5002.ipynb
│   ├── nodes.json
│   └── transaction.json
└── README.md
Condensed preview — 59 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (237K chars).
[
  {
    "path": ".gitignore",
    "chars": 10,
    "preview": ".DS_Store\n"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 1 - Primeros pasos/ERC20.sol",
    "chars": 4005,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 < 0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./SafeMath.so"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 1 - Primeros pasos/SafeMath.sol",
    "chars": 860,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n\n// Implementacion de"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 1 - Primeros pasos/conceptos_basicos.sol",
    "chars": 623,
    "preview": "// SPDX-License-Identifier: MIT\n//Inidicamos la version\npragma solidity >=0.4.4 <0.7.0;\n//Importar el archivo ERC20.sol "
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 10 - Fábrica de Smart Contracts/factory.sol",
    "chars": 587,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.9.0;\npragma experimental ABIEncoderV2;\n\ncontract SmartContrac"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 2 - Propiedades transacciones y bloques/funciones_globales.sol",
    "chars": 949,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract funciones_globales{\n   "
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 2 - Propiedades transacciones y bloques/keccak256.sol",
    "chars": 898,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/Modificadores.sol",
    "chars": 715,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/Operadores.sol",
    "chars": 1272,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicando la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract Operadores{\n    \n    //"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/casteo_variables.sol",
    "chars": 752,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract casteo{\n    \n    //Ejempl"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/comparar_strings.sol",
    "chars": 492,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/enum.sol",
    "chars": 1213,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract Ejemplos_enumeraciones{\n "
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/mas_variables.sol",
    "chars": 982,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/unidades_tiempo.sol",
    "chars": 750,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract timepo{\n    \n    //Unid"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 3 - Tipos de variables y operadores/variables_enteras.sol",
    "chars": 733,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract enteros{\n    \n    //Var"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 4 - Estructuras de datos/Estructuras.sol",
    "chars": 1211,
    "preview": "// SPDX-License-Identifier: MIT\n//Especificamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract Estructuras{\n    \n "
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 4 - Estructuras de datos/arrays.sol",
    "chars": 868,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract Arrays{\n    \n    //Arra"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 4 - Estructuras de datos/mappings.sol",
    "chars": 1310,
    "preview": "// SPDX-License-Identifier: MIT\n//Especificamos la version\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncode"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/causas_beneficas.sol",
    "chars": 1959,
    "preview": "// SPDX-License-Identifier: MIT\n//Especificamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract causasBeneficas{\n  "
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/eventos.sol",
    "chars": 960,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\ncontract Eventos{\n   "
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/funciones.sol",
    "chars": 1730,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicamos la version\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/modificadores.sol",
    "chars": 1256,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicamos la version\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 5 - Funciones/returns.sol",
    "chars": 1828,
    "preview": "// SPDX-License-Identifier: MIT\n//Especificamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract ValoresDeRetorno{\n "
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 6 - Bucles y condicionales/bucle_for.sol",
    "chars": 1390,
    "preview": "// SPDX-License-Identifier: MIT\n//Especificar la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract bucle_for{\n    \n    /"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 6 - Bucles y condicionales/bucle_while.sol",
    "chars": 1532,
    "preview": "// SPDX-License-Identifier: MIT\n//Especificamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract bucle_while{\n    \n "
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 6 - Bucles y condicionales/sentencia_if.sol",
    "chars": 2138,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract sentencia_if{\n    \n    //"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 7 - Interactuando con otros Smart Contracts/Banco.sol",
    "chars": 631,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract Banco{\n    \n    //Defin"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 7 - Interactuando con otros Smart Contracts/Cliente.sol",
    "chars": 907,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\n//import \"./Banco.sol\";\nimport {Banco, Banco2} from \"./B"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 7 - Interactuando con otros Smart Contracts/herencia.sol",
    "chars": 1357,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicamos la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract Banco{\n    \n    //Defin"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 7 - Interactuando con otros Smart Contracts/librerias.sol",
    "chars": 712,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\n\nlibrary Operaciones{\n    \n    func"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 8 - Funciones avanzadas/internal_external.sol",
    "chars": 1119,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 0.7.0;\n\ncontract Comida{\n    \n    struct pl"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 8 - Funciones avanzadas/modifier.sol",
    "chars": 1351,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\n\ncontract Modifer{\n    \n    \n    //"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 8 - Funciones avanzadas/require.sol",
    "chars": 1069,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 9 - SafeMath/SafeMath.sol",
    "chars": 892,
    "preview": "// SPDX-License-Identifier: MIT\n// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIE"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 9 - SafeMath/SafeMath_comentada.sol",
    "chars": 999,
    "preview": "// SPDX-License-Identifier: MIT\n// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIE"
  },
  {
    "path": "BLOQUE 1 - Conceptos básicos de Solidity/Tema 9 - SafeMath/ejemplo_uso.sol",
    "chars": 639,
    "preview": "// SPDX-License-Identifier: MIT\n//Indicar la version\npragma solidity >=0.4.4 <0.7.0;\nimport \"./SafeMath.sol\";\n\n\ncontract"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/Creación y uso de un Token ERC-20/ERC20.sol",
    "chars": 4005,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 < 0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./SafeMath.so"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/Creación y uso de un Token ERC-20/SafeMath.sol",
    "chars": 860,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n\n// Implementacion de"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/DISNEY/ERC20.sol",
    "chars": 3535,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./SafeMath.sol"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/DISNEY/SafeMath.sol",
    "chars": 860,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n\n// Implementacion de"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/DISNEY/disney.sol",
    "chars": 10589,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./ERC20.sol\";\n\n"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/Evaluaciones universitarias con un Smart Contract/notas.sol",
    "chars": 2617,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 < 0.7.0;\npragma experimental ABIEncoderV2;\n\n// -----------------"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/LOTERIA/ERC20.sol",
    "chars": 3537,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./SafeMath.sol"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/LOTERIA/SafeMath.sol",
    "chars": 859,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n\n// Implementacion de"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/LOTERIA/loteria.sol",
    "chars": 7535,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./ERC20.sol\";\n\n"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/OMS/oms.sol",
    "chars": 5649,
    "preview": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.0 < 0.9.0;\npragma experimental ABIEncoderV2;\n\ncontract OMS_COV"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/VOTACION/votacion.sol",
    "chars": 4928,
    "preview": "//SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n\n// ------------------"
  },
  {
    "path": "BLOQUE 2 - Proyectos reales con Smart Contracts/VOTACION/votacion_tarea.sol",
    "chars": 6290,
    "preview": "//SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n\n// ------------------"
  },
  {
    "path": "BLOQUE 3 - Proyecto final de curso/PROYECTO FINAL - Servicio de telemedicina/ERC20.sol",
    "chars": 3056,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./SafeMath.sol"
  },
  {
    "path": "BLOQUE 3 - Proyecto final de curso/PROYECTO FINAL - Servicio de telemedicina/MedicalInsurance.sol",
    "chars": 25651,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./OperacionesB"
  },
  {
    "path": "BLOQUE 3 - Proyecto final de curso/PROYECTO FINAL - Servicio de telemedicina/OperacionesBasicas.sol",
    "chars": 1032,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\nimport \"./SafeMath.sol"
  },
  {
    "path": "BLOQUE 3 - Proyecto final de curso/PROYECTO FINAL - Servicio de telemedicina/SafeMath.sol",
    "chars": 860,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity >=0.4.4 <0.7.0;\npragma experimental ABIEncoderV2;\n\n\n// Implementacion de"
  },
  {
    "path": "BLOQUE 4 - Creación de una Blockchain con Python/blockchain.ipynb",
    "chars": 18642,
    "preview": "{\"nbformat\":4,\"nbformat_minor\":0,\"metadata\":{\"colab\":{\"name\":\"blockchain.ipynb\",\"provenance\":[],\"collapsed_sections\":[],"
  },
  {
    "path": "BLOQUE 5 - Creación de una Criptomoneda con Python/criptomoneda_5000.ipynb",
    "chars": 22978,
    "preview": "{\"cells\":[{\"cell_type\":\"markdown\",\"metadata\":{\"id\":\"aHsnfVt1Yuh2\"},\"source\":[\"\\u003cdiv style=\\\"width: 100%; clear: both"
  },
  {
    "path": "BLOQUE 5 - Creación de una Criptomoneda con Python/criptomoneda_5001.ipynb",
    "chars": 24111,
    "preview": "{\"cells\":[{\"cell_type\":\"markdown\",\"metadata\":{\"id\":\"aHsnfVt1Yuh2\"},\"source\":[\"\\u003cdiv style=\\\"width: 100%; clear: both"
  },
  {
    "path": "BLOQUE 5 - Creación de una Criptomoneda con Python/criptomoneda_5002.ipynb",
    "chars": 24103,
    "preview": "{\"cells\":[{\"cell_type\":\"markdown\",\"metadata\":{\"id\":\"aHsnfVt1Yuh2\"},\"source\":[\"\\u003cdiv style=\\\"width: 100%; clear: both"
  },
  {
    "path": "BLOQUE 5 - Creación de una Criptomoneda con Python/nodes.json",
    "chars": 160,
    "preview": "{\n    \"nodes\" : [\"http://716a-34-74-138-151.ngrok.io\",\n               \"http://ca2a-34-83-45-204.ngrok.io\",\n             "
  },
  {
    "path": "BLOQUE 5 - Creación de una Criptomoneda con Python/transaction.json",
    "chars": 59,
    "preview": "{\n    \"sender\" : \"\",\n    \"receiver\" : \"\",\n    \"amount\" : \n}"
  },
  {
    "path": "README.md",
    "chars": 5210,
    "preview": "# Comunidad Blockchain\n\n* LinkedIn del Instructor: https://www.linkedin.com/in/joanamengual7/\n\n* Perfil de Udemy: https:"
  }
]

About this extraction

This page contains the full source code of the joaneeet7/Solidity GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 59 files (212.7 KB), approximately 60.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!