├── .gitignore ├── 01 - Hello World ├── HelloWorld.sol └── exercise.md ├── 02 - Counter ├── Counter.sol └── exercise.md ├── 03 - Exercises ├── 1-Variables.sol ├── 2-Conditionals.sol ├── 3-For.sol ├── 4-Arrays&for.sol └── 5-EtherStorage.sol ├── 03 - Storage ├── Storage.sol └── exercise.md ├── 04 - Simple Auction ├── SimpleAuction.sol └── exercise.md ├── 05 - Vote system ├── VoteSystem.sol └── exercise.md ├── 06 - HotelGame ├── HotelGame.sol └── exercise.md ├── 07 - Tokens ERC-20 ├── ERC20.sol ├── Erc20-BannedList.sol ├── Erc20-fee.sol └── exercises.md ├── 08 - Vesting ├── Vesting.sol └── exercises.md ├── 09 - Faucet ├── Faucet.sol └── exercises.md ├── 10 - ERC721 ├── ERC721.sol └── exercises.md ├── 11 - Marketplace ├── Marketplace.sol └── exercises.md ├── 12 - Crowfunding └── Crowfunding.sol ├── README.md ├── University Nft └── UniversityNft.sol ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .openzeppelin 3 | templates -------------------------------------------------------------------------------- /01 - Hello World/HelloWorld.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract HelloWorld { 5 | string mensaje= "Hello World!"; 6 | 7 | function getGreeting() public view returns (string memory) { 8 | return mensaje; 9 | } 10 | } -------------------------------------------------------------------------------- /01 - Hello World/exercise.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "Modifie the message" 2 | 3 | Dificult: Basic 4 | 5 | Objective: Familiarizarse con la modificación de variables en un contrato. 6 | 7 | 8 | 1. Modificar el mensaje 9 | A. Agrega una función llamada setGreeting que permita cambiar el mensaje de saludo. 10 | B. Que solo el propietario del contrato pueda modificar el mensaje. 11 | 12 | 2. Añadir contador de saludos 13 | A. Crear un contador de saludos, cada ves que se llame a la funcion 'getGreeting' que este contador suba en 1. 14 | B. Crear una funcion que permita obtener la cantidad de saludos. -------------------------------------------------------------------------------- /02 - Counter/Counter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract Counter { 5 | uint256 count; 6 | 7 | function getCount() public view returns (uint256) { 8 | return count; 9 | } 10 | 11 | function incrementCount() public { 12 | count++; 13 | } 14 | 15 | function decrementCount() public { 16 | count--; 17 | } 18 | } -------------------------------------------------------------------------------- /02 - Counter/exercise.md: -------------------------------------------------------------------------------- 1 | # Exercises: "Count this" 2 | 3 | Dificult: Basic 4 | 5 | ### 1. Establecer límite mínimo y máximo 6 | **Objective: Añadir restricciones para evitar que el contador se salga de ciertos límites.** 7 | 8 | - Agrega dos variables de estado: uint256 private minCount y uint256 private maxCount. 9 | - Modifica las funciones incrementCount y decrementCount para que solo aumenten o disminuyan count si el resultado permanece dentro de los límites minCount y maxCount. 10 | - Crea funciones para permitir al propietario del contrato cambiar los valores de minCount y maxCount. 11 | 12 | 13 | ### 2: Agregar función de reseteo 14 | **Objetivo: Permitir al propietario restablecer el contador a un valor específico.** 15 | 16 | - Agrega una función llamada resetCount que acepte un argumento uint256 llamado newValue. 17 | - Esta función debería permitir que solo el propietario del contrato restablezca el contador (count) al valor newValue. -------------------------------------------------------------------------------- /03 - Exercises/1-Variables.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /*****************/ 5 | /* BASICS */ 6 | /*****************/ 7 | 8 | contract exerciseOne { 9 | /** @dev Crea una función que declare una variable local dentro de ella y 10 | * otra variable global con el mismo nombre. 11 | * ¿Cuál es la variable que se utiliza dentro de la función? 12 | */ 13 | 14 | // variable global o variable de estado 15 | 16 | 17 | function fLocal() public returns(){ 18 | // variable local 19 | 20 | //return var 21 | } 22 | } 23 | 24 | continue exerciseTwo{ 25 | /** 26 | * Define una variable de estado (state variable) en un contrato y 27 | * crea una función para modificar su valor. 28 | */ 29 | } 30 | 31 | continue exerciseTree{ 32 | /** 33 | * Declara una variable local en una función y trata de acceder a ella desde otra función en el mismo contrato. 34 | * ¿Qué sucede? ¿Puedes solucionarlo? 35 | */ 36 | } 37 | 38 | continue exerciseFour{ 39 | /** 40 | * Crea un contrato que tenga una variable privada 41 | * y una función pública que permita acceder a su valor. 42 | */ 43 | } -------------------------------------------------------------------------------- /03 - Exercises/2-Conditionals.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /*****************/ 5 | /* BASICS */ 6 | /*****************/ 7 | 8 | contract exerciseOne { 9 | /** 10 | * Escribe una función que tome dos números como parámetros 11 | * y use un condicional if para determinar cuál de los dos es mayor. 12 | */ 13 | 14 | } 15 | contract exerciseTwo { 16 | /** 17 | * Implementa una función que tome un número como entrada 18 | * y devuelva "Par" si es divisible por 2 y "Impar" si no lo es. 19 | 20 | * HINT: No olvides usar el modificador de variable 'memory' cuando sea requerido 21 | */ 22 | 23 | } 24 | contract exerciseTree { 25 | /** 26 | * Crea un contrato con una función que requiera una condición para ejecutar una acción 27 | * por ejemplo : 28 | - que solo se pueda ejecutar si el msg.sender es un address en particular 29 | - transferir tokens solo si el remitente es el propietario del contrato. 30 | */ 31 | 32 | } -------------------------------------------------------------------------------- /03 - Exercises/3-For.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /*****************/ 5 | /* BASICS */ 6 | /*****************/ 7 | 8 | contract exerciseOne { 9 | /** 10 | * Crea una función que utilice un bucle for para sumar los números del 1 al 20 y devolver el resultado 11 | */ 12 | 13 | } 14 | contract exerciseTwo { 15 | /** 16 | * Implementa una función que tome un array de uint como parámetro 17 | * y use un bucle for para calcular la suma de sus elementos. 18 | */ 19 | 20 | } 21 | contract exerciseTree { 22 | /** 23 | * 24 | */ 25 | 26 | } -------------------------------------------------------------------------------- /03 - Exercises/4-Arrays&for.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /*****************/ 5 | /* BASICS */ 6 | /*****************/ 7 | 8 | contract exerciseOne{ 9 | /** 10 | * Define una función que recorra un array de direcciones Ethereum 11 | * y devuelva el número de direcciones válidas (no vacías). 12 | vector: 13 | address[10] public ethereumAddresses = [ 14 | 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4, 15 | address(0), 16 | 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2, 17 | 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c, 18 | address(0), 19 | address(0), 20 | 0x6b175474e89094c44da98b954eedeac495271d0f, 21 | address(0), 22 | address(0), 23 | 0xdD870fA1b7C4700F2BD7f44238821C26f7392148a 24 | ]; 25 | */ 26 | 27 | } 28 | 29 | contract exerciseTwo{ 30 | /** 31 | * Crea un contrato que almacene una lista de nombres en un vector mediante una funcion 32 | * y luego implementa una función para buscar un nombre específico en la lista. 33 | */ 34 | 35 | } 36 | 37 | contract exerciseTree{ 38 | /** 39 | * Desarrolla una función que tome un array de números por parametro 40 | * y devuelva la suma de los números pares en el array. 41 | */ 42 | 43 | } 44 | contract exerciseFour{ 45 | /** 46 | * Desarrolla una función que tome un array de números por parametro que: 47 | * - cambie los numeros impares por numeros pares, 48 | * - Cuente la cantidad de numeros que cambio. 49 | * - Retorne el nuevo editado y la cantidad de numeros cambiados 50 | */ 51 | 52 | } -------------------------------------------------------------------------------- /03 - Exercises/5-EtherStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | /** @dev Crea un contrato de billetera simple en Solidity que permita a los usuarios depositar y retirar Ethe. 5 | * Puedes usar el contrato Storage para inspirarte. Recuerda que el manejo de Ether en un contrato tiene unas consideraciones especiales 6 | * Puedes Usar este template para completar el ejercicio o reescribirlo a tu manera: 7 | */ 8 | 9 | contract Wallet { 10 | address public owner; 11 | uint public balance; 12 | 13 | // Constructor: asignar el propietario inicial y establecer el saldo en cero 14 | constructor() { 15 | 16 | } 17 | 18 | // Función para depositar Ether en la billetera 19 | function deposit() /**MODIFICADOREs */ { 20 | 21 | } 22 | 23 | // Función para permitir al propietario retirar Ether 24 | function withdraw(uint amount) /**MODIFICADOREs */ { 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /03 - Storage/Storage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity >=0.8.2 <0.9.0; 3 | 4 | // Este codigo puede no funcionar. Porque? 5 | 6 | contract Storage { 7 | uint256[] number; 8 | 9 | function store(uint256 num) public { 10 | uint length = number.length; 11 | number[length] = num; 12 | } 13 | 14 | function retrieve(uint index) public view returns (uint256){ 15 | return number[index]; 16 | } 17 | } -------------------------------------------------------------------------------- /03 - Storage/exercise.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "Bugflow" 2 | 3 | Dificult: Medium 4 | 5 | 1. Corregir el error de desbordamiento: *Identificar y corregir el error que causa un desbordamiento en el contrato.* 6 | A. Actualmente, la función store intenta almacenar un número en la posición length del array number. Sin embargo, esto causará un desbordamiento ya que el índice válido máximo es length - 1. 7 | B. Corrige el contrato para que se pueda almacenar el número correctamente en el array. 8 | 9 | 2. Agregar función para obtener informacion del array: *Practicar cómo obtener información sobre la longitud del array desde fuera del contrato.* 10 | A. Agrega una función pública llamada getArrayLength que permita a cualquiera obtener la longitud actual del array number. 11 | B. Agregar una funcion publica que retorne el array completo. -------------------------------------------------------------------------------- /04 - Simple Auction/SimpleAuction.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | pragma solidity ^0.8.4; 3 | 4 | contract SimpleAuction { 5 | // Parameters of the auction. Times are either 6 | // absolute unix timestamps (seconds since 1970-01-01) 7 | // or time periods in seconds. 8 | address payable public beneficiary; 9 | uint public auctionEndTime; 10 | 11 | // Current state of the auction. 12 | address public highestBidder; 13 | uint public highestBid; 14 | 15 | // Allowed withdrawals of previous bids 16 | mapping(address => uint) pendingReturns; 17 | 18 | // Set to true at the end, disallows any change. 19 | // By default initialized to `false`. 20 | bool ended; 21 | 22 | 23 | event HighestBidIncreased(address bidder, uint amount); 24 | event AuctionEnded(address winner, uint amount); 25 | 26 | // Errors that describe failures. 27 | /// The auction has already ended. 28 | error AuctionAlreadyEnded(); 29 | /// There is already a higher or equal bid. 30 | error BidNotHighEnough(uint highestBid); 31 | /// The auction has not ended yet. 32 | error AuctionNotYetEnded(); 33 | /// The function auctionEnd has already been called. 34 | error AuctionEndAlreadyCalled(); 35 | 36 | /// Create a simple auction with `biddingTime` 37 | /// seconds bidding time on behalf of the 38 | /// beneficiary address `beneficiaryAddress`. 39 | constructor( 40 | uint biddingTime, 41 | address payable beneficiaryAddress 42 | ) { 43 | beneficiary = beneficiaryAddress; 44 | auctionEndTime = block.timestamp + biddingTime; 45 | } 46 | 47 | /// Bid on the auction with the value sent 48 | /// together with this transaction. 49 | /// The value will only be refunded if the 50 | /// auction is not won. 51 | function bid() external payable { 52 | if (block.timestamp > auctionEndTime) 53 | revert AuctionAlreadyEnded(); 54 | 55 | if (msg.value <= highestBid) 56 | revert BidNotHighEnough(highestBid); 57 | 58 | if (highestBid != 0) { 59 | pendingReturns[highestBidder] += highestBid; 60 | } 61 | highestBidder = msg.sender; 62 | highestBid = msg.value; 63 | emit HighestBidIncreased(msg.sender, msg.value); 64 | } 65 | 66 | /// Withdraw a bid that was overbid. 67 | function withdraw() external returns (bool) { 68 | uint amount = pendingReturns[msg.sender]; 69 | if (amount > 0) { 70 | pendingReturns[msg.sender] = 0; 71 | if (!payable(msg.sender).send(amount)) { 72 | pendingReturns[msg.sender] = amount; 73 | return false; 74 | } 75 | } 76 | return true; 77 | } 78 | function auctionEnd() external { 79 | // 1. Conditions 80 | if (block.timestamp < auctionEndTime) 81 | revert AuctionNotYetEnded(); 82 | if (ended) 83 | revert AuctionEndAlreadyCalled(); 84 | 85 | // 2. Effects 86 | ended = true; 87 | emit AuctionEnded(highestBidder, highestBid); 88 | 89 | // 3. Interaction 90 | beneficiary.transfer(highestBid); 91 | } 92 | } -------------------------------------------------------------------------------- /04 - Simple Auction/exercise.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "I buy that" 2 | 3 | Dificult: medium 4 | 5 | 1. Añadir una función para extender el tiempo de subasta 6 | Task: Permitir al beneficiario (dueño) de la subasta extender el tiempo de la subasta si lo desea.* 7 | A. Agrega una función pública llamada extendAuction que acepte un argumento uint256 llamado extraTime. 8 | B. Esta función debería permitir que solo el beneficiario (dueño) de la subasta extienda la fecha de finalización de la subasta en extraTime segundos adicionales. 9 | 10 | 2. Agregar función para finalizar manualmente la subasta. *Permitir al beneficiario finalizar manualmente la subasta en caso de que desee detenerla antes de que expire el tiempo.* 11 | A. Agrega una función pública llamada endAuctionManually que permita al beneficiario finalizar manualmente la subasta. 12 | B. Esta función debería transferir el monto de la oferta más alta al beneficiario y emitir el evento AuctionEnded con la información apropiada. -------------------------------------------------------------------------------- /05 - Vote system/VoteSystem.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity >=0.7.0 <0.9.0; 4 | 5 | contract Ballot { 6 | 7 | struct Voter { 8 | uint weight; // el peso se acumula mediante delegación 9 | bool voted; // si es verdadero, la persona ya votó 10 | address delegate; // persona a la que se delega 11 | uint vote; // índice de la propuesta votada 12 | } 13 | 14 | struct Proposal { 15 | // Si puedes limitar la longitud a un número determinado de bytes, 16 | // siempre usa uno de bytes1 a bytes32, ya que son mucho más baratos 17 | bytes32 name; // nombre corto (hasta 32 bytes) 18 | uint voteCount; // número de votos acumulados 19 | } 20 | 21 | address public chairperson; 22 | 23 | mapping(address => Voter) public voters; 24 | 25 | Proposal[] public proposals; 26 | 27 | /** 28 | * @dev Crea una nueva votación para elegir una de las 'proposalNames'. 29 | * @param proposalNames nombres de las propuestas 30 | */ 31 | constructor(bytes32[] memory proposalNames) { 32 | chairperson = msg.sender; 33 | voters[chairperson].weight = 1; 34 | 35 | for (uint i = 0; i < proposalNames.length; i++) { 36 | // 'Proposal({...})' crea un objeto temporal 37 | // Proposal y 'proposals.push(...)' 38 | // lo agrega al final de 'proposals'. 39 | proposals.push(Proposal({ 40 | name: proposalNames[i], 41 | voteCount: 0 42 | })); 43 | } 44 | } 45 | 46 | /** 47 | * @dev Otorga a 'voter' el derecho a votar en esta votación. Solo puede ser llamada por el 'chairperson'. 48 | * @param voter dirección del votante 49 | */ 50 | function giveRightToVote(address voter) public { 51 | require( 52 | msg.sender == chairperson, 53 | "Solo el chairperson puede otorgar el derecho a votar." 54 | ); 55 | require( 56 | !voters[voter].voted, 57 | "El votante ya ha votado." 58 | ); 59 | require(voters[voter].weight == 0); 60 | voters[voter].weight = 1; 61 | } 62 | 63 | /** 64 | * @dev Delega tu voto al votante 'to'. 65 | * @param to dirección a la que se delega el voto 66 | */ 67 | function delegate(address to) public { 68 | Voter storage sender = voters[msg.sender]; 69 | require(!sender.voted, "Ya has votado."); 70 | require(to != msg.sender, "La auto-delegacion no esta permitida."); 71 | 72 | while (voters[to].delegate != address(0)) { 73 | to = voters[to].delegate; 74 | 75 | // Se encontró un bucle en la delegación, no está permitido. 76 | require(to != msg.sender, "Se encontro un bucle en la delegacion."); 77 | } 78 | sender.voted = true; 79 | sender.delegate = to; 80 | Voter storage delegate_ = voters[to]; 81 | if (delegate_.voted) { 82 | // Si el delegado ya ha votado, 83 | // se añade directamente al número de votos 84 | proposals[delegate_.vote].voteCount += sender.weight; 85 | } else { 86 | // Si el delegado aún no ha votado, 87 | // se añade a su peso. 88 | delegate_.weight += sender.weight; 89 | } 90 | } 91 | 92 | /** 93 | * @dev Da tu voto (incluidos los votos delegados a ti) a la propuesta 'proposals[proposal].name'. 94 | * @param proposal índice de la propuesta en el array proposals 95 | */ 96 | function vote(uint proposal) public { 97 | Voter storage sender = voters[msg.sender]; 98 | require(sender.weight != 0, "No tienes derecho a votar"); 99 | require(!sender.voted, "Ya has votado."); 100 | sender.voted = true; 101 | sender.vote = proposal; 102 | 103 | // Si 'proposal' está fuera del rango del array, 104 | // esto generará automáticamente una excepción y revertirá todos 105 | // los cambios. 106 | proposals[proposal].voteCount += sender.weight; 107 | } 108 | 109 | /** 110 | * @dev Calcula la propuesta ganadora teniendo en cuenta todos los votos anteriores. 111 | * @return winningProposal_ índice de la propuesta ganadora en el array proposals 112 | */ 113 | function winningProposal() public view returns (uint winningProposal_) { 114 | uint winningVoteCount = 0; 115 | for (uint p = 0; p < proposals.length; p++) { 116 | if (proposals[p].voteCount > winningVoteCount) { 117 | winningVoteCount = proposals[p].voteCount; 118 | winningProposal_ = p; 119 | } 120 | } 121 | } 122 | 123 | /** 124 | * @dev Llama a la función winningProposal() para obtener el índice del ganador contenido en el array proposals y luego 125 | * @return winnerName_ el nombre del ganador 126 | */ 127 | function winnerName() public view returns (bytes32 winnerName_) { 128 | winnerName_ = proposals[winningProposal()].name; 129 | } 130 | } -------------------------------------------------------------------------------- /05 - Vote system/exercise.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "I vote for that" 2 | 3 | Dificult: medium 4 | 5 | 1. Restringir la votación a un período de tiempo específico 6 | Task: Agregar una funcionalidad para permitir que el presidente de la votación defina un período de tiempo durante el cual se puede votar. 7 | - Agrega dos variables de estado llamadas votingStartTime y votingEndTime para representar el inicio y el final del período de votación. 8 | - Modifica la función giveRightToVote para que solo el chairperson pueda otorgar el derecho a votar a los votantes durante el período de votación. 9 | - Asegúrate de que la función vote solo se pueda llamar durante el período de votación. 10 | 11 | 2. Limitar la cantidad de propuestas 12 | Task: Limitar la cantidad máxima de propuestas que se pueden agregar a la votación. 13 | - Agrega una variable de estado llamada maxProposals para definir el límite máximo de propuestas. 14 | - Modifica el constructor para que solo se permita agregar hasta maxProposals propuestas. 15 | - Asegúrate de que la función vote solo acepte índices de propuestas válidos (de 0 a maxProposals-1). -------------------------------------------------------------------------------- /06 - HotelGame/HotelGame.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.16; 3 | 4 | contract TheHotelGame { 5 | struct Hotel { 6 | uint256 coins; 7 | uint256 money; 8 | uint256 money2; 9 | uint256 yield; 10 | uint256 timestamp; 11 | uint256 hrs; 12 | address ref; 13 | uint256 refs; 14 | uint256 refDeps; 15 | uint8[8] Stars; 16 | } 17 | mapping(address => Hotel) public hotels; 18 | uint256 public totalStars; 19 | uint256 public totalHotels; 20 | uint256 public totalInvested; 21 | address public manager = msg.sender; 22 | 23 | function addCoins(address ref) public payable { 24 | uint256 coins = msg.value / 2e13; 25 | require(coins > 0, "Zero coins"); 26 | address user = msg.sender; 27 | totalInvested += msg.value; 28 | if (hotels[user].timestamp == 0) { 29 | totalHotels++; 30 | ref = hotels[ref].timestamp == 0 ? manager : ref; 31 | hotels[ref].refs++; 32 | hotels[user].ref = ref; 33 | hotels[user].timestamp = block.timestamp; 34 | } 35 | ref = hotels[user].ref; 36 | hotels[ref].coins += (coins * 7) / 100; 37 | hotels[ref].money += (coins * 100 * 3) / 100; 38 | hotels[ref].refDeps += coins; 39 | hotels[user].coins += coins; 40 | payable(manager).transfer((msg.value * 3) / 100); 41 | } 42 | 43 | function withdrawMoney() public { 44 | address user = msg.sender; 45 | uint256 money = hotels[user].money; 46 | hotels[user].money = 0; 47 | uint256 amount = money * 2e11; 48 | payable(user).transfer(address(this).balance < amount ? address(this).balance : amount); 49 | } 50 | 51 | function collectMoney() public { 52 | address user = msg.sender; 53 | syncHotel(user); 54 | hotels[user].hrs = 0; 55 | hotels[user].money += hotels[user].money2; 56 | hotels[user].money2 = 0; 57 | } 58 | 59 | function upgradeHotel(uint256 floorId) public { 60 | require(floorId < 8, "Max 8 floors"); 61 | address user = msg.sender; 62 | syncHotel(user); 63 | hotels[user].Stars[floorId]++; 64 | totalStars++; 65 | uint256 Stars = hotels[user].Stars[floorId]; 66 | hotels[user].coins -= getUpgradePrice(floorId, Stars); 67 | hotels[user].yield += getYield(floorId, Stars); 68 | } 69 | 70 | function sellHotel() public { 71 | collectMoney(); 72 | address user = msg.sender; 73 | uint8[8] memory Stars = hotels[user].Stars; 74 | totalStars -= Stars[0] + Stars[1] + Stars[2] + Stars[3] + Stars[4] + Stars[5] + Stars[6] + Stars[7]; 75 | hotels[user].money += hotels[user].yield * 24 * 14; 76 | hotels[user].Stars = [0, 0, 0, 0, 0, 0, 0, 0]; 77 | hotels[user].yield = 0; 78 | } 79 | 80 | function getStars(address addr) public view returns (uint8[8] memory) { 81 | return hotels[addr].Stars; 82 | } 83 | 84 | function syncHotel(address user) internal { 85 | require(hotels[user].timestamp > 0, "User is not registered"); 86 | if (hotels[user].yield > 0) { 87 | uint256 hrs = block.timestamp / 3600 - hotels[user].timestamp / 3600; 88 | if (hrs + hotels[user].hrs > 24) { 89 | hrs = 24 - hotels[user].hrs; 90 | } 91 | hotels[user].money2 += hrs * hotels[user].yield; 92 | hotels[user].hrs += hrs; 93 | } 94 | hotels[user].timestamp = block.timestamp; 95 | } 96 | 97 | function getUpgradePrice(uint256 floorId, uint256 workerId) internal pure returns (uint256) { 98 | if (workerId == 1) { 99 | return [500, 1500, 4500, 13500, 40500, 120000, 365000, 1000000][floorId]; 100 | } 101 | if (workerId == 2) return [625, 1800, 5600, 16800, 50600, 150000, 456000, 1200000][floorId]; 102 | if (workerId == 3) return [780, 2300, 7000, 21000, 63000, 187000, 570000, 1560000][floorId]; 103 | if (workerId == 4) return [970, 3000, 8700, 26000, 79000, 235000, 713000, 2000000][floorId]; 104 | if (workerId == 5) return [1200, 3600, 11000, 33000, 98000, 293000, 890000, 2500000][floorId]; 105 | revert("Incorrect workerId"); 106 | } 107 | 108 | function getYield(uint256 floorId, uint256 workerId) internal pure returns (uint256) { 109 | if (workerId == 1) return [41, 130, 399, 1220, 3750, 11400, 36200, 104000][floorId]; 110 | if (workerId == 2) return [52, 157, 498, 1530, 4700, 14300, 45500, 126500][floorId]; 111 | if (workerId == 3) return [65, 201, 625, 1920, 5900, 17900, 57200, 167000][floorId]; 112 | if (workerId == 4) return [82, 264, 780, 2380, 7400, 22700, 72500, 216500][floorId]; 113 | if (workerId == 5) return [103, 318, 995, 3050, 9300, 28700, 91500, 275000][floorId]; 114 | revert("Incorrect workerId"); 115 | } 116 | } 117 | 118 | /* TODO: 119 | * make tax in public var (line 41) 120 | * Can money2 can be deleted? 121 | * puedo hacer el juego gratis? 122 | * aumentarlo a 72hrs? 123 | * eliminar sis de referidos 124 | */ -------------------------------------------------------------------------------- /06 - HotelGame/exercise.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "That hotel!" 2 | 3 | *El contrato "TheHotelGame" es un juego basado en Solidity que permite a los usuarios administrar hoteles y ganar recompensas* 4 | 5 | Dificult: medium 6 | 7 | 1. Agregar un límite de tiempo para vender hoteles 8 | Task: Restringir la venta de hoteles para que solo se pueda realizar después de cierto tiempo de propiedad. 9 | - Agrega una variable de estado llamada saleLockTime para definir el tiempo mínimo de propiedad (en segundos) antes de que se pueda vender un hotel. 10 | - Modifica la función sellHotel para que solo permita vender un hotel si el usuario ha sido dueño del hotel durante al menos saleLockTime segundos 11 | 12 | 2. Agregar un evento para notificar la venta de un hotel 13 | Task: Agregar un evento que se emita cada vez que se vende un hotel. 14 | - Agrega un evento llamado HotelSold que incluya información relevante sobre la venta del hotel, como el usuario que vendió el hotel y el dinero recibido. -------------------------------------------------------------------------------- /07 - Tokens ERC-20/ERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.9; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MyToken is ERC20 { 7 | constructor() ERC20("MyToken", "MTK") { 8 | _mint(msg.sender, 11 * 10 ** decimals()); 9 | } 10 | } -------------------------------------------------------------------------------- /07 - Tokens ERC-20/Erc20-BannedList.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeandroCDN/solidity-project-examples/8d5d1b274c6abed49706064e753f60e0e303e47e/07 - Tokens ERC-20/Erc20-BannedList.sol -------------------------------------------------------------------------------- /07 - Tokens ERC-20/Erc20-fee.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeandroCDN/solidity-project-examples/8d5d1b274c6abed49706064e753f60e0e303e47e/07 - Tokens ERC-20/Erc20-fee.sol -------------------------------------------------------------------------------- /07 - Tokens ERC-20/exercises.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "Learn basic standar!" 2 | 3 | Dificult: Hard 4 | 5 | 1. Agregar función mint para el owner y establecer un límite máximo de suministro 6 | Task: Permitir al propietario del contrato "MyToken" (owner) crear nuevos tokens mediante la función mint, y asegurarse de que el suministro total no supere un límite máximo. 7 | - Agrega una variable de estado llamada maxSupply para definir el límite máximo de suministro de tokens. 8 | - Implementa una función pública llamada mint que permita al owner crear nuevos tokens y agregarlos al balance de su cuenta. 9 | - Asegúrate de que el total de tokens creados mediante la función mint no supere el valor de maxSupply. 10 | 11 | 2. Agregar un fee de transacción 12 | Task: Implementar un mecanismo de tarifa de transacción para cada transferencia de tokens realizada en el contrato "MyToken". 13 | - Agrega una variable de estado llamada transactionFee para definir el porcentaje de tarifa que se aplicará a cada transferencia. 14 | - Modifica la función transfer para deducir la tarifa de transacción antes de realizar la transferencia y enviar la tarifa al owner del contrato. 15 | - Puedes hacer este ejercicio haciendo overide de la funcion '_beforeTokenTransfer()"? 16 | 17 | -------------------------------------------------------------------------------- /08 - Vesting/Vesting.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.16; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | /* 8 | * @title : Vesting 9 | * @author: @LenLabiano 10 | * @notice: a vesting contract for youtube tutorial 11 | */ 12 | contract Vesting is Ownable { 13 | bool stateVesting; 14 | uint startVesting; 15 | uint interval = 30 days; 16 | uint totalCurrency; 17 | uint8 maxClaims = 10; 18 | 19 | IERC20 public currency; 20 | mapping(address => uint) public totalAmounts; 21 | mapping(address => uint) public totalClaims; 22 | 23 | constructor(address currency_) { 24 | require(currency_ != address(0), "Must be a token address"); 25 | currency = IERC20(currency_); 26 | } 27 | 28 | modifier beforeVestingStart() { 29 | require(!stateVesting, "Only when the Vesting dont start"); 30 | _; 31 | } 32 | 33 | /* 34 | ** @dev: owner can register accounts before start vesting. If one address appers twice, 35 | ** the ammount is added 36 | ** @param accounts: List of account in vesting 37 | ** @param amounts: Amount of total vesting for each account 38 | */ 39 | function resgisterVesting(address[] memory accounts, uint[] memory amounts) public onlyOwner beforeVestingStart(){ 40 | 41 | uint length = accounts.length; 42 | require(length == amounts.length); 43 | 44 | uint totalCurrency_; 45 | 46 | for(uint i; i = totalCurrency, "Not enough balance"); 68 | stateVesting = true; 69 | startVesting = block.timestamp; 70 | } 71 | 72 | function claimTokens() external { 73 | require(stateVesting, "Vesting not started yet"); 74 | address user = msg.sender; 75 | uint amount = totalAmounts[user]; 76 | uint currentClaim = totalClaims[user]++; 77 | require(amount > 0); 78 | require(block.timestamp >= startVesting + interval * ( currentClaim + 1), "Error: next claim instance not available yet"); 79 | require(currentClaim <= 10); 80 | uint totalAmount = (amount * 10)/100; 81 | 82 | currency.transfer(user, totalAmount); 83 | } 84 | 85 | } 86 | 87 | //posibles tareas 88 | /* 89 | - hacer que el contrato sea reutilizable. 90 | - Completar la funcion remove acounts 91 | - permitir que el contrato use Crypto( matic en polygon, eth en ethereum (funciones payables)) 92 | */ -------------------------------------------------------------------------------- /08 - Vesting/exercises.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "Wait a time." 2 | 3 | Dificult: 4 | 5 | 1. Múltiples tipos de token 6 | Task: Permitir que el contrato de vesting pueda manejar múltiples tipos de tokens, no solo el token específico que se definió en el constructor. 7 | - Agrega una función pública llamada setCurrency que permita solo al owner cambiar el token manejado por el contrato de vesting. 8 | - Agrega una función pública llamada setCurrency que permita al owner cambiar el token manejado por el contrato de vesting. 9 | - Ten cuidado con los problemas que podria ocacionar cambiar el token, con vesting ya en marcha. 10 | 11 | 2. Completar la función removeAccounts 12 | Task: Permitir al owner del contrato eliminar cuentas registradas antes de que comience el vesting. 13 | - Asegúrate de que el estado del vesting no haya comenzado y que solo el owner pueda llamar a esta función. 14 | -------------------------------------------------------------------------------- /09 - Faucet/Faucet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.18; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | /* 8 | * @Author: remember use npm intall to install all openzepellin dependencies 9 | */ 10 | contract Faucet is Ownable{ 11 | uint dailyAmountPerWallet; 12 | uint claimCooldown = 1 days; 13 | IERC20 public token; 14 | mapping(address wallet => uint lastClaim) public claims; 15 | 16 | constructor(address token_, uint dailyAmount){ 17 | token = IERC20(token_); 18 | dailyAmountPerWallet = dailyAmount; 19 | } 20 | 21 | function fillFaucet(uint amount) public { 22 | token.transferFrom(msg.sender, address(this), amount); 23 | } 24 | 25 | function claim() public{ 26 | require(token.balanceOf(address(this)) > dailyAmountPerWallet, "not enough balance"); 27 | require(claims[msg.sender] + claimCooldown < block.timestamp, "need more time" ); 28 | claims[msg.sender] = block.timestamp + claimCooldown; 29 | token.transfer(msg.sender, dailyAmountPerWallet); 30 | } 31 | 32 | function changeDailyAmount(uint dailyAmount) public onlyOwner{ 33 | dailyAmountPerWallet = dailyAmount; 34 | } 35 | 36 | function changeClaimCooldown(uint claimCooldown_) public onlyOwner{ 37 | claimCooldown = claimCooldown_; 38 | } 39 | } -------------------------------------------------------------------------------- /09 - Faucet/exercises.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "my tokens are your tokens" 2 | 3 | Dificult: 4 | 5 | 1. Agregar función para retirar fondos 6 | Task: Permitir al propietario del contrato retirar fondos sobrantes que no se han reclamado en el grifo. 7 | - Agrega una función pública llamada withdrawFunds que permita al owner retirar los fondos que no se han reclamado en el grifo. 8 | - Asegúrate de que solo el owner pueda llamar a esta función y que los fondos se envíen a la dirección del owner. 9 | 10 | 2. Agregar función para pausar/reanudar el grifo 11 | Task: Permitir al owner pausar o reanudar la funcionalidad del grifo para evitar que se realicen reclamaciones durante un período de tiempo. 12 | - Puedes usar la libreria de openzeppelin especificamente para esto 13 | - Agrega una variable de estado llamada isFaucetPaused para controlar el estado del grifo 14 | - Modifica la función claim para que solo se puedan realizar reclamaciones si el grifo no está pausado. 15 | 16 | 3. Agregar función para cambiar el token del grifo 17 | Task: Permitir al owner cambiar el token manejado por el contrato de grifo. 18 | - Agrega una función pública llamada setToken que permita al owner cambiar el token manejado por el contrato de grifo. 19 | - Asegúrate de que solo el owner pueda llamar a esta función y que el nuevo token sea una dirección válida de token. -------------------------------------------------------------------------------- /10 - ERC721/ERC721.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.9; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | contract MyToken is ERC721, Ownable { 8 | constructor() ERC721("MyToken", "MTK") {} 9 | 10 | function safeMint(address to, uint256 tokenId) public onlyOwner { 11 | _safeMint(to, tokenId); 12 | } 13 | } -------------------------------------------------------------------------------- /10 - ERC721/exercises.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "this is my" 2 | 3 | Dificult: 4 | 5 | 1. Agregar metadatos a los tokens 6 | Task: Permitir que cada token de ERC721 tenga metadatos asociados para representar características únicas. 7 | - Agrega una variable de estado llamada tokenURI para almacenar las URL base de los metadatos. 8 | - Modifica la función safeMint para que cada nuevo token tenga un URI único asociado. 9 | - Agrega una función pública llamada setTokenURI que permita al owner cambiar el URI base de los metadatos. 10 | - OpenSea tiene una libreria para implementar esto. 11 | -------------------------------------------------------------------------------- /11 - Marketplace/Marketplace.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | 8 | contract Marketplace is Ownable{ 9 | struct NFT { 10 | address nftAddress; 11 | uint256 tokenId; // ID del NFT 12 | address owner; // Dirección del dueño actual del NFT 13 | uint256 price; // Precio del NFT en la moneda del marketplace 14 | bool isListed; // Indica si el NFT está listado para la venta 15 | } 16 | 17 | IERC20 currency; 18 | mapping(address nftAddress => mapping(uint256 nftId=> NFT)) public nfts; 19 | 20 | 21 | event NFTListed(uint256 indexed tokenId, uint256 price); 22 | event NFTSold(uint256 indexed tokenId, uint256 price, address buyer); 23 | 24 | constructor(address currency_) { 25 | currency = IERC20(currency_); 26 | } 27 | 28 | function setCurrency(address currency_) public onlyOwner { 29 | currency = IERC20(currency_); 30 | } 31 | 32 | // Función para listar un NFT para la venta en el marketplace, with aproved function 33 | function listNFT(address nftAddress, uint256 tokenId, uint256 price) external { 34 | require(msg.sender == IERC721(nftAddress).ownerOf(tokenId), "You are not the owner of this NFT"); 35 | require(!nfts[nftAddress][tokenId].isListed, "NFT is already listed for sale"); 36 | 37 | nfts[nftAddress][tokenId] = NFT(nftAddress,tokenId, msg.sender, price, true); 38 | emit NFTListed(tokenId, price); 39 | } 40 | 41 | // Función para comprar un NFT del marketplace 42 | function buyNFT(address nftAddress, uint256 tokenId) external { 43 | NFT storage nft = nfts[nftAddress][tokenId]; 44 | require(nft.isListed, "NFT is not listed for sale"); 45 | 46 | uint256 price = nft.price; 47 | address seller = nft.owner; 48 | 49 | currency.transferFrom(msg.sender, seller, price); 50 | IERC721(nftAddress).safeTransferFrom(seller, msg.sender, tokenId); 51 | 52 | nft.isListed = false; 53 | nft.owner = msg.sender; 54 | 55 | emit NFTSold(tokenId, price, msg.sender); 56 | } 57 | } 58 | /* task 59 | * Unlist func 60 | * Market Fees 61 | * Remake all contract to hold in this contract all nfts on sale 62 | * ale under time, like only open for 6 days 63 | */ -------------------------------------------------------------------------------- /11 - Marketplace/exercises.md: -------------------------------------------------------------------------------- 1 | ## Exercises: "my tokens are your tokens" 2 | 3 | Dificult: 4 | 5 | 1. Agregar función para retirar NFT no vendidos 6 | Task: Permitir a los propietarios de NFT retirar sus NFTs del marketplace si no han sido vendidos. 7 | - Agrega una función pública llamada withdrawNFT que permita al propietario de un NFT retirar su NFT del marketplace si no ha sido vendido. 8 | - Asegúrate de que solo el propietario del NFT pueda llamar a esta función y que el NFT esté listado para la venta. 9 | - Actualiza el estado del NFT para indicar que ya no está listado para la venta. 10 | 11 | 2. Agregar función para cambiar el precio de un NFT listado 12 | Task: Permitir al propietario de un NFT listado cambiar el precio de venta, solo en el caso de que el nft n. 13 | - Agrega una función pública llamada changePrice que permita al propietario de un NFT listado cambiar el precio de venta. 14 | - Asegúrate de que solo el propietario del NFT pueda llamar a esta función y que el NFT esté listado para la venta. 15 | - Actualiza el precio del NFT en el estado del marketplace. 16 | 17 | 18 | -------------------------------------------------------------------------------- /12 - Crowfunding/Crowfunding.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.19; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "@openzeppelin/contracts/utils/Strings.sol"; 7 | 8 | /* **In progress** */ 9 | 10 | contract Crowdfunding is ERC721, Ownable { 11 | using Strings for uint256; 12 | 13 | struct Project { 14 | bytes32 encryptedTitle; 15 | bytes32 encryptedDescription; 16 | uint256 targetAmount; 17 | uint256 deadline; 18 | uint256 totalAmount; 19 | bool funded; 20 | } 21 | 22 | Project[] public projects; 23 | mapping(uint256 => address) public projectCreators; 24 | 25 | constructor() ERC721("Crowdfunding", "CF") {} 26 | 27 | function createProject( 28 | bytes32 encryptedTitle, 29 | bytes32 encryptedDescription, 30 | uint256 targetAmount, 31 | uint256 deadline 32 | ) external { 33 | uint256 projectId = projects.length; 34 | projects.push( 35 | Project(encryptedTitle, encryptedDescription, targetAmount, deadline, 0, false) 36 | ); 37 | projectCreators[projectId] = msg.sender; 38 | _safeMint(msg.sender, projectId); 39 | } 40 | 41 | function getProject(uint256 projectId) external view returns (bytes32, bytes32, uint256, uint256, uint256, bool) { 42 | require(_exists(projectId), "Invalid project ID"); 43 | Project memory project = projects[projectId]; 44 | return ( 45 | project.encryptedTitle, 46 | project.encryptedDescription, 47 | project.targetAmount, 48 | project.deadline, 49 | project.totalAmount, 50 | project.funded 51 | ); 52 | } 53 | 54 | function contribute(uint256 projectId) external payable { 55 | require(_exists(projectId), "Invalid project ID"); 56 | require(!projects[projectId].funded, "Project already funded"); 57 | require( 58 | block.timestamp <= projects[projectId].deadline, 59 | "Project deadline passed" 60 | ); 61 | 62 | projects[projectId].totalAmount = projects[projectId].totalAmount + msg.value; 63 | 64 | if (projects[projectId].totalAmount >= projects[projectId].targetAmount) { 65 | projects[projectId].funded = true; 66 | } 67 | } 68 | 69 | function withdrawFunds(uint256 projectId) external { 70 | require(projects[projectId].funded, "Project not funded"); 71 | require( 72 | msg.sender == projectCreators[projectId], 73 | "Only project creator can withdraw funds" 74 | ); 75 | 76 | uint256 amount = projects[projectId].totalAmount; 77 | projects[projectId].totalAmount = 0; 78 | payable(msg.sender).transfer(amount); 79 | } 80 | 81 | function getProjectURI(uint256 tokenId) public view returns (string memory) { 82 | require(_exists(tokenId), "Invalid token ID"); 83 | } 84 | 85 | function tokenURI(uint256 tokenId) public view override returns (string memory) { 86 | return getProjectURI(tokenId); 87 | } 88 | 89 | function baseURI() public pure returns (string memory) { 90 | return "https://example.com/projects/"; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

# solidity-project-exples

3 | 4 | ## 📝 About 5 | 6 | This repository contains a series of Solidity mini-projects aimed at providing practical examples to help you learn the language's scope and standards. Each project is accompanied by a detailed explanation available on YouTube. 7 | 8 | ## 🗒 Challenges 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 |
DayProjectFechaYoutube linkCodigo
00MOCKdd/mm/yyTwitterYoutube
01HelloWorld10/04/23TUTORIALRepositoryChallenge
02Counter10/04/23TUTORIALRepositoryChallenge
03Storage11/04/23No videoRepositoryChallenge
04SimpleAuction30/04/23No VideoRepositoryChallenge
05Vote-System20/06/23No-VideoRepositoryRepository
06HotelGame10/04/23Cooming SoonRepositoryChallenge
07ERC-20 tokens10/04/23PlayListRepositoryChallenge
08Vesting21/06/23Cooming SoonRepositoryChallenge
09Faucet02/07/23No-videoRepositoryChallenge
10ERC72130/07/23TUTORIALRepositoryChallenge
11Marketplace30/07/23No-videoRepositoryChallenge
12Crowfunding30/07/23No-videoRepositoryChallenge
-------------------------------------------------------------------------------- /University Nft/UniversityNft.sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeandroCDN/solidity-project-examples/8d5d1b274c6abed49706064e753f60e0e303e47e/University Nft/UniversityNft.sol -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solidity-project-exples", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "solidity-project-exples", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@openzeppelin/contracts": "^4.9.2" 13 | } 14 | }, 15 | "node_modules/@openzeppelin/contracts": { 16 | "version": "4.9.2", 17 | "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.9.2.tgz", 18 | "integrity": "sha512-mO+y6JaqXjWeMh9glYVzVu8HYPGknAAnWyxTRhGeckOruyXQMNnlcW6w/Dx9ftLeIQk6N+ZJFuVmTwF7lEIFrg==" 19 | } 20 | }, 21 | "dependencies": { 22 | "@openzeppelin/contracts": { 23 | "version": "4.9.2", 24 | "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.9.2.tgz", 25 | "integrity": "sha512-mO+y6JaqXjWeMh9glYVzVu8HYPGknAAnWyxTRhGeckOruyXQMNnlcW6w/Dx9ftLeIQk6N+ZJFuVmTwF7lEIFrg==" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solidity-project-exples", 3 | "version": "1.0.0", 4 | "description": "A list of examples of solidity for tutorials", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/LeandroCDN/solidity-project-exples.git" 12 | }, 13 | "author": "LeanLabiano", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/LeandroCDN/solidity-project-exples/issues" 17 | }, 18 | "homepage": "https://github.com/LeandroCDN/solidity-project-exples#readme", 19 | "dependencies": { 20 | "@openzeppelin/contracts": "^4.9.2" 21 | } 22 | } 23 | --------------------------------------------------------------------------------