No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Establecer tipos de datos personalizados con Struct Types

15/21
Recursos

La complejidad de un contrato inteligente puede ser de un nivel tan alto que no nos alcancen los tipos de variables que este lenguaje tiene para ofrecer y debamos declarar nuestros tipos de datos personalizados.

Estructuras de datos

Puedes declarar un nuevo tipo de dato conocido como estructuras que permiten agrupar N cantidad de variables relacionadas entre sí, cada una de un tipo diferente.

Si tienes conocimiento en programación orientada a objetos, sabrás lo que es una clase y cómo instanciar la misma te genera un objeto. También puedes entender el uso de las estructuras similar que las Interfaces en TypeScript. Conjuntos de datos relacionados que suelen representar un registro. Solidity implementa el concepto de estructura inspirado en C/C++.

  1. Utiliza la palabra reservada struct para crear una estructura de datos. Así podrás tener dentro cada propiedad la estructura y su respectivo tipo.
struct Persona {
    string nombre;
    string apellido;
    uint edad;
}
  1. Genera una variable de este tipo, basta con invocar el constructor de la estructura y asignarle el tipo a la variable.
Persona p = Persona("Lionel", "Messi", 35);
  1. Emplea los datos dentro de una estructura de manera intuitiva, ten en cuenta que es prácticamente igual a la utilización de un objeto.
p.nombre;     // Lionel
p.apellido;   // Messi
p.edad;       // 35

Dentro de una estructura, podrás tener otra estructura, arrays o cualquier otro tipo de dato.

Estos conocimientos te permitirán desarrollar mejores contratos y, sobre todo, más limpios. Cuando necesitamos manipular una gran cantidad de datos, podemos agruparlos de forma lógica en una estructura para garantizar un acceso más organizado.


Contribución creada por: Luis Enrique Herrera y Kevin Fiorentino (Platzi Contributors).

Aportes 36

Preguntas 7

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Struct types

Solidity permite al usuario crear su propio tipo de datos en forma de estructura. La estructura contiene un grupo de elementos con un tipo de datos diferente. Generalmente, se usa para representar un registro. Para definir una estructura se utiliza la palabra clave struct, que crea un nuevo tipo de datos.

struct <structure_name> {  
   <data type> variable_1;  
   <data type> variable_2; 
}

Más información aquí

Anteriormente la variable state estaba declarada como string e inicializada con un valor, así: string public state = "Opened", en está clase se cambió el tipo de dato a uint, pero sin inicializar el valor de la variable quedando ahora así: uint public state. Al no darle un valor inicial la variable adquiere un valor por defecto, para el tipo de datos uint este valor por defecto es 0. Más información en la Documentación de Solidity

Solución reto 5

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract Crowfunding{
    
    struct Project {
        int id;
        string name;
        bool isActive;
        address payable owner;
        uint founds;
        uint goal;
    }
    
    Project public project;
    
    constructor(string memory _name, uint _goal) {
        project = Project(1, _name, true, payable(msg.sender), 0, _goal);
    }
    
    event FundProject(address donor, uint quantity);
    
    event ChangedState(bool isActive);
    
    modifier onlyOwner() {
        require(project.owner == msg.sender, "You are not the project owner");
        _;
    }
    
    modifier notOwner() {
        require(project.owner != msg.sender, "You cannot transfer to your own project");
        _;
    }
    
    modifier onlyWhenActive() {
        require(project.isActive, "This project is not active.");
        _;
    }
    
    function fundProject() public payable notOwner onlyWhenActive {
        require(msg.value > 0, "You cannot fund 0 eth");
        project.owner.transfer(msg.value);
        project.founds += msg.value;
        emit FundProject(msg.sender, msg.value);
    }
    
    function changeProjectState() public onlyOwner {
        project.isActive = !project.isActive;
        emit ChangedState(project.isActive);
    }
}

Struct Types

struct Hero {
  string name;
  uint age;
  uint power;
  string team;
}
Hero cap = Hero('Cap',103, 80, 'Avengers');
cap.name  //Cap
cap.age   //103
cap.power  //80
cap.team  //Avengers

Aqui les dejo la forma de comparar strings en solidity:
keccak256(bytes(“open”)) == keccak256(bytes(“open”))

Batman: Poder “Soy millonario” XD

Los struct me recuerdan a las “class” o “interface” en otros lenguajes.

My solution:

contract CrowdFunding {

    struct Data {
        string id;
        string name;
        string description;
        uint fundraisingGoal;
        address payable owner;
        uint state;
        uint totalFunds;
    }

    Data public data;

    constructor(string memory _id, string memory _name, string memory _description, uint _fundraisingGoal) {
        data = Data(
        data.id = _id,
        data.name = _name,
        data.description = _description,
        data.fundraisingGoal = _fundraisingGoal,
        data.owner = payable(msg.sender),
        data.state = 0,
        data.totalFunds = 0
        );
    }

Recuerden que al convertir la variable “state” de string a uint, deben hacerlo igual en:

Event ProjectStateChanged()
function changeProjectState(uint newState)

Recuerden que Solidity es altamente tipado sino se hacen los cambios el compilador les dara error.

Cumpliendo el reto

// SPDX-License-Identifier: SEE LICENSE IN LICENSE

pragma solidity >= 0.7.0;

contract crowdfunding {
  struct Project {
    string id;
    string name;
    string description;
    address payable author; //who create o represent the project
    uint state; 
    uint funds; // to acumulate project funds
    uint fundraisingGoal; // the goal of the funding
    }

    Project public project;
    constructor(string memory _id, string memory _name, string memory _description, uint  _fundraisingGoal) {
        project = Project(
            _id,
            _name,
            _description,
            payable(msg.sender),
            0,
            0,
            _fundraisingGoal
        );
    }

  modifier notFundFronAuthor {
      require(
          msg.sender != project.author,
          "Author don't funding his ouw project"
      );
      _;
  }

  event SendFunding(
      address funder,
      uint fund
  );

  event RaisingFundGoal(
      string idProject,
      uint fundRaising,
      string mensaje
  );

  function fundProject() public payable notFundFronAuthor{
    require(msg.value > 0,"Fund value must be greater then 0");
    require(project.state != 1,"The project can not receive funds, it's closed");
    project.author.transfer(msg.value);
    project.funds += msg.value;
    emit SendFunding(msg.sender, msg.value);
    if (project.funds >= project.fundraisingGoal) {
        emit RaisingFundGoal(
            project.id, 
            project.funds,
            "fundRaisingGoal reached");
    }
  }

    modifier onlyAuthorOrRaisingGoal {
        require(
            msg.sender == project.author || project.funds >= project.fundraisingGoal,
            "Only author can change state or if the fundraidingGoal is raising"
        );
        _; // identifica desde donde se inserta la función, define cuando se continua la función
    }

    event ChangeState(
        string idProject,
        uint newState
    );

    function changeProjectState(uint newState) public onlyAuthorOrRaisingGoal {
        require(
            newState == 1 || newState == 0,
            "Invalid new state. It'll be 0 to Opened and 1 to Closed"
        );
        project.state = newState;
        emit ChangeState(project.id, newState);
    }
}

Mi solución:

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract Project {

address private owner;
string public state = "open";

constructor() {
    owner = msg.sender;
}

modifier difOwner() {
    require(
        msg.sender != owner,
        "Owner can't fund the project"
    );
    // La función es insertada en donde aparece este símbolo
    _;
}

modifier onlyOwnerState() {
    require(
        msg.sender == owner,
        "Only owner can change the project name"
    );
    // La función es insertada en donde aparece este símbolo
    _;
}

error projectClosed(string message, string _state);
event addFunds(string message, address donator, uint amount );

function fundProject(address payable _donator) public payable difOwner  {
    require(
        msg.value > 0,
        "Debe ingresar un monto mayor a 0" 
    );

    if(keccak256(abi.encodePacked(state)) == keccak256(abi.encodePacked("closed"))) {
        string memory msgError = "El proyecto esta cerrado";
        revert projectClosed(msgError, state);
    }else {
        _donator.transfer(msg.value);
        uint amount = msg.value;
        emit addFunds("Gracias por su aporte", _donator, amount);
    }   
}

event changeState(string message, string oldState, string newState);

function changeProjectState(string memory _newState) public onlyOwnerState {
    string memory oldState = state;
    state = _newState;

    emit changeState("El autor ha cambiado el estado", oldState, state);
}

}

Excelente explicación !

El uso de las struct types, es para reducir el coste del gas. Ya que con este tipo podemos agrupar elementos. que pueden ser usados en mapping o array

Gracias profe excelentes clases!

  • Mi proyecto hasta el momento con el reto 5:

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract Crowfounding {

struct Project {
    string id;
    string name;
    string description;
    address payable owner;
    bool receive_funds;
    uint state;
    uint funds;
    uint fundraisingGoal;
}

Project public project;

constructor(string memory _name, string memory _description, uint _fundraisingGoal) {
    project = Project(
        "1", _name, _description, payable(msg.sender), true, 0, 0, _fundraisingGoal
    );
}

modifier notOwnerPay() {
    require (
        msg.sender != project.owner,
        "The author can't funder the project"
    );
    _;
}

modifier onlyOwnerChangeState() {
    require (
        msg.sender == project.owner,
        "Only owner can change the state of project"
    );
    _;
}

modifier onlyOwnerChangeName() {
    require (
        msg.sender == project.owner,
        "Only owner can change the project name"
    );
    // La funcion es insertada en donde aparece este simbolo
    // define cuando continua la funcion
    _;
}

event FundProject(
    string name,
    string description,
    address owner,
    bool receive_funds,
    uint state,
    uint value
);

event ChangeProjectState(
    string name,
    bool receive_funds,
    uint newState
);

function fundProject() public payable notOwnerPay {
    require(project.state != 1, "The project can not receive funds");
    require(msg.value > 0, "Fund value must be greater than 0");
    if(project.receive_funds) {
        project.owner.transfer(msg.value);
        project.funds += msg.value;
    }
    emit FundProject(project.name, project.description, project.owner, project.receive_funds, project.state, msg.value);
}

function changeFundProject() public payable {
    if (project.funds > project.fundraisingGoal) {
        project.receive_funds = false;
    }
}

function changeProjectState(uint newState) public onlyOwnerChangeState {
    require(project.state != newState, "New state must be different");
    project.state = newState;
    emit ChangeProjectState(project.name, project.receive_funds, newState);
}

function receiveFunds() public view returns (bool) {
    return project.receive_funds;
}


function changeProjectName(string memory _name) public onlyOwnerChangeName {
    project.name = _name;
}

// Los eventos permiten conectar lo que pasa dentro de la blockchain, con el exterior

}

function fundProject() public payable isNotAuthor {
    require(state!=1,'Project has to be Opened');
    author.transfer(msg.value);
    require(msg.value>0,'Fund has to be more than zero');
    funds += msg.value;
    emit ProjectFunded(id, msg.value);
}

function changeProjectState(uint newState) public isAuthor {
    require(state!=newState,'Project has to change');
    state = newState;
    emit ProjectStateChanged(id, newState);
}

Tambien es util crearlos fuera del contrato e importarlos en los contratos donde es sea necesario 👈🏻
Aca una referencia https://solidity-by-example.org/structs/

RESUMEN CLASE 15:
STRUCT TYPES

  • Tipos personalizados que agrupan variables.

RETO 5:

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract CrowdFunding {
    struct Project {
        string id;
        string name;
        string description;
        address payable author;
        uint state;
        uint funds;
        uint fundraisingGoal;
    }

    Project public project;

    event ProjectFunded(string projectId, uint value);

    event ProjectStateChanged(string id, uint state);

    constructor(
        string memory _id,
        string memory _name,
        string memory _description,
        uint256 _fundraisingGoal
    ) {
        project = Project(
            _id,
            _name,
            _description,
            payable(msg.sender),
            0,
            0,
            _fundraisingGoal
        );
    }

    modifier isAuthor() {
        require(
            project.author == msg.sender,
            "You need to be the project author"
        );
        _;
    }

    modifier isNotAuthor() {
        require(
            project.author != msg.sender,
            "As author you can not fund your own project"
        );
        _;
    }

    function fundProject() public payable isNotAuthor {
        require(project.state != 1, "The project can not receive funds");
        require(msg.value > 0, "Fund value must be greater than 0");
        project.author.transfer(msg.value);
        project.funds += msg.value;
        emit ProjectFunded(project.id, msg.value);
    }

    function changeProjectState(uint256 newState) public isAuthor {
        require(project.state != newState, "New state must be different");
        project.state = newState;
        emit ProjectStateChanged(project.id, newState);
    }
}

Los struct types se usan para crear un tipo que contenga más de una característica que lo describa

Ejemplo: Hero: Nombre, Edad, Poder, Team

Puede sonar obvio, pero es algo de lo que siempre debemos estar pendientes.

En el momento en que realizamos un cambio en nuestro contrato, debemos hacer un nuevo deploy para poder ver que estos cambios son tomados en cuenta. De otra forma, estaremos es observando la última versión compilada que no presentaba dichos cambios.

// SPDX-License-Identifier: UNLICENSED

pragma solidity >=0.7.0 <=0.9.0;

contract crowFundingProyect{
    address payable public owner;
    string public projectName;
    string public description;
    uint256 public targetFunds;
    uint256 public currentFunds;
    uint256 public id;
    uint public state;
    uint open = 0;
    uint closed = 1;
    
    constructor(string memory project_Name, string memory _description, uint256 _id, uint256 target_Funds_Wei, uint open_Zero_closed_One){
         projectName = project_Name;
         description = _description;
         id = _id;
         targetFunds = target_Funds_Wei;
         owner = payable(msg.sender);
         state = open_Zero_closed_One;
    }

    modifier notOwner() {
        require( msg.sender != owner,
         "You cannot fund your project..." );_;                
    }    

    modifier isOwner() {
        require( msg.sender == owner,
         "only owner, sorry..." );_;
    }        
    
    function fund() public payable notOwner {
        require( msg.value + currentFunds < targetFunds, "its amount exceeds the limit of the project's funding objective, try a smaller amount..." );
        require( currentFunds < targetFunds, "the project has already reached its target funding limit..." );
        require( msg.value != 0, "You are transferring 0 funds..." );
        require( state == 0, "the project is closed" );
         owner.transfer(msg.value); 
         currentFunds += msg.value;
         emit senderAndFund(msg.sender, msg.value, currentFunds);
    } 

    event senderAndFund(
         address depositSender,
         uint valueSender,
         uint CurrentTotalFund
    );

    function changeDataProject(string memory change_ProjectName, string memory change_Description, uint256 change_ID, uint256 change_TargetFunds) public isOwner { 
         projectName = change_ProjectName;
         description = change_Description;
         id = change_ID;
         targetFunds = change_TargetFunds;
    }

    function changeStateProject(uint change_State) public isOwner {
        require( state != change_State, "You are changing the status to the previous one" );
        require( change_State == 0 || change_State == 1, "( 0 = open ) and ( 1 = closed ) you can only write one of the two above numbers" );
        state = change_State;
        if(change_State == 0){
         change_State = open;
        }else if(change_State == 1){
         change_State = closed;
        }
        emit currentState(state);
    }

    event currentState(
         uint stateFinal
    );

}

Recordé mi época programando en C++ en la universidad. Dicho lenguaje también utiliza la palabra clave Struct para definir interfaces de datos.
Solidity claramente está inspirado en C++ y tiene cosas de Javascript también.

Los Structs son como diccionatrios en python 😃

Funcion de los struct

Mi codigo falla cuando quiero setear el estado de nuevo a 0, la consola tira:

transact to CrowFunding.changeProjectState errored: VM error: out of gas.

out of gas
	The transaction ran out of gas. Please increase the Gas Limit.

Que puede ser ? Este es el SC:

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract CrowFunding {
    string public id;
    string public name;
    string public description;
    address payable public author;
    uint public state;
    uint public funds;
    uint public fundraisingGoal;

    event ProjectStateChanged(
        string newState
    );

    event FundsAdded (
        uint256 amount,
        address sender
    );

    error NotZeroValues(uint256 amount);
    error UnknownState(uint state);

    constructor(string memory _id, string memory _name, string memory _description, uint _fundraisingGoal) {
        id = _id;
        name = _name;
        description = _description;
        fundraisingGoal = _fundraisingGoal;
        author = payable(msg.sender);
    }

    modifier notAuthor {
        require(msg.sender != author, "Only people who are not the author can fund the project");
        // la function que tenga el modifier se inserta debajo de este simbolo
        _;
    }

    modifier onlyAuthor {
        require(msg.sender == author, "Only author can chanage the project state");
        // la function que tenga el modifier se inserta debajo de este simbolo
        _;
    }

    function fundProject() public payable notAuthor {
        require(state != 1, "The project is closed for new funds");
        require(msg.value > 0, "Fund must be greater than 0");
        author.transfer(msg.value);
        funds += msg.value;
        emit FundsAdded(funds, msg.sender);
    }

    function changeProjectState(uint newState) public onlyAuthor {
        state = newState;
        emit ProjectStateChanged("Project state changed");
    }
}

RETO #5 con Struct

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.7.0 <0.9.0;

contract projectFundPlatzi{
    struct Datos {  
        string  name;
        bool  isFundable;
        uint  deposits;
        uint  depositsGoal;
        uint  depositTest;
        address  autor;
        string  state;
        string  tokenLog;
        string  tokenFeedback;
    }
    Datos public dato;
    constructor(
        string memory _name, string  memory _state, uint _depositsGoal
        ){
            dato.name = _name;
            dato.isFundable = true;
            dato.deposits = 0;
            dato.depositsGoal=_depositsGoal;
            dato.autor = msg.sender; 
            dato.state = _state;
            dato.tokenLog = "Log: project status changed";
            dato.tokenFeedback = "Feedback: Gracias";
    }
    error stateNotDefined (string newState);

    event newFundFeedback(
        address autor,
        uint256 deposit,
        string Feedback
    );
    event newFundLog(
        uint256 depositsGoal,
        uint256 deposits,
        string Log
    );
    modifier notOnlyOwnerPay{
        require (dato.autor != msg.sender, "El propietario no puede abonar fondos al proyecto" );
        //la funcion es insertada donde aparece este simbolo _
        _;
    }
    modifier ownerRequired {
        require (msg.sender == dato.autor, "Esta accion es restringida al propietario.");
        _;
    }
    function viewDeposits() public view returns (uint){
        return dato.deposits;
    }

    function viewRemaining() public view returns(uint256){
        return dato.depositsGoal - dato.deposits;
    }

    function fundProject(address payable benefactor) public payable notOnlyOwnerPay {     
        require (msg.value > 0, "No se acepta abonos sin valor.");
        dato.depositTest = dato.deposits + msg.value;
       
        if (dato.isFundable == true && dato.depositTest <= dato.depositsGoal) {
            benefactor.transfer(msg.value);
            dato.deposits +=  msg.value;
            emit newFundFeedback (dato.autor, msg.value,dato.tokenFeedback);
        }
    
    }

    function changeProjectState(string memory _newState) public ownerRequired{
        require (keccak256(abi.encodePacked(_newState))  != keccak256(abi.encodePacked(dato.state)), "El nombre de estado es igual al actual y no es actualizable");
        if (keccak256(abi.encodePacked(_newState)) == keccak256(abi.encodePacked("Open"))){
            dato.isFundable = true;
            dato.state = "Open";
        }else if (keccak256(abi.encodePacked(_newState)) == keccak256(abi.encodePacked("Closed"))){
            dato.isFundable = false;
            dato.state = "Closed";
        } else {
            revert stateNotDefined (_newState);
        }          
       dato.isFundable = !dato.isFundable;
       emit newFundLog (dato.depositsGoal, dato.deposits, dato.tokenLog);
    }

Comparto mi solución:

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract PlatziPrueba {
    string public id;
    string public name;
    string public description;
    address payable public author;
    uint public stateCode = 1;
    string public stateDescription = "Opened";
    uint public funds;
    uint public fundralsInGoal;

    constructor (string memory _id, string memory _name, string memory _description, uint _fundralsInGoal) {
        id = _id;
        name = _name;
        description = _description;
        fundralsInGoal = _fundralsInGoal;
        author = payable(msg.sender);
    }

    modifier ownerNotAported() {
        require(msg.sender != author,
        "El propio owner no pude aportar a su mismo proyecto..!");

        _;
    }

    event eFoundProject(
        string id,
        uint value
    );

    function foundProject() public payable ownerNotAported{
        require(stateCode == 1, "No se puede aportar en estado cerrado");
        require(msg.value > 0, "Por favor ingresar un monto mayor a cero");
        author.transfer(msg.value);
        funds += msg.value;
        emit eFoundProject(id, msg.value);
    }

    modifier onlyOwnerChangeState() {
        require(msg.sender == author,
        "Solo el owner puede cambiar el estado...!");

        _;
    }

    event eChangeState(
        string id,
        string state
    );

    error errorChangeState(uint stateCode);

    function changeProjectState(uint newstate) public onlyOwnerChangeState {
        require(newstate != stateCode, "no puedes cambiar de estado a su mismo estado");
        if(newstate == 1) {
            stateCode = newstate;
            stateDescription = "Opened";
        } else if(newstate == 2) {
            stateCode = newstate;
            stateDescription = "Closed";
        } else {
            revert errorChangeState(newstate);
        }
        
        emit eChangeState(id, stateDescription);
    }
}

Asemejo mucho los struct types a las clases en Python

Me hacía muy mal no ver el código con los diccionarios o struct. Ahora no tardo tanto en leer y modificar el código

¿Como se comparan strings? si al igual que yo no querían cambiar el tipo de dato de la variable state pueden comprar strings como una cadena de bloques y el código esta acá:
require(keccak256(abi.encodePacked(status)) != keccak256(abi.encodePacked(“closed”)), "Lo sentimos el proyecto esta cerrado ");

Este es mi avance del proyecto con el reto #5:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Proyecto_Platzi{

    struct projectInfo{
        string name;
        string description;
        string owner;
        address payable ownerWallet;
        uint state;
        uint goal;
        uint currentFund;
    }

    projectInfo public CrowFundingProject;

    constructor(string memory _name, string memory _owner, string memory _description, uint _goal){
        CrowFundingProject.name = _name;
        CrowFundingProject.description = _description;
        CrowFundingProject.owner = _owner;
        CrowFundingProject.ownerWallet = payable(msg.sender);
        CrowFundingProject.state = 0;
        CrowFundingProject.goal = _goal;
        CrowFundingProject.currentFund = 0;
    }

    modifier onlyOwner() {
        require(
            msg.sender == CrowFundingProject.ownerWallet,
            "Only owner can change the project state"
        );
        //la función es insertada en donde aparece este simbolo
        _;
    }


    modifier differentToTheOwner() {
        require(
            msg.sender != CrowFundingProject.ownerWallet,
            "The owner can't fund the project"
        );
        //la función es insertada en donde aparece este simbolo
        _;
    }

    event ChangeState(
        uint previousState,
        uint newState
    );

    event FundValueGiven(
        uint fundGiven,
        uint valueToGoal,
        string greetingMessage
    );

    function fundProject() public payable differentToTheOwner{
        require(CrowFundingProject.state != 1, "Sorry, this project is closed and cannot receive funds");
        require(msg.value > 0, "Sorry, fund value must be greater than 0, try again");
        CrowFundingProject.ownerWallet.transfer(msg.value);
        CrowFundingProject.currentFund += msg.value;
        emit FundValueGiven(msg.value, (CrowFundingProject.goal - msg.value), "Thanks for your contribution");
    }

    function changeProjectState(uint newState) public onlyOwner{
        require(CrowFundingProject.state != newState, "Sorry, to change the state you must put a different state from the current one");
        emit ChangeState(CrowFundingProject.state, newState);
        CrowFundingProject.state = newState;
    }
}

Reto #5

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.0;

contract CrowdFunding {
    struct Project {
        string id;
        string name;
        address payable authorAddress;
        bool isFundable;
        uint targetAmount;
        uint amountFunded;
    }
    
    Project public project;

    // Events
    event projectFunded(
        address sender,
        uint amount
    );
    
    event projectStateChanged (
        string projectName,
        string message
    );
    // ./Events
    
    constructor(string memory _id, string memory _projectName, uint _targetAmount){
        project = Project(_id, _projectName, payable(msg.sender), true, _targetAmount, 0);
    }
    
    function fundProject() public payable isNotAuthor canFund {
        require(msg.value > 0, 'The funded amount must be greater than 0');
        project.authorAddress.transfer(msg.value);
        project.amountFunded += msg.value;
        emit projectFunded(msg.sender, msg.value);
    }
    
    function changeProjectState(string calldata newState) public isAuthor {
        string memory currentState = project.isFundable ? string('opened') : string('closed');
        
        require(keccak256(abi.encode(newState)) == keccak256(abi.encode('opened')) || keccak256(abi.encode(newState)) == keccak256(abi.encode('closed')), 'This state is not defined');
        require(keccak256(abi.encode(newState)) != keccak256(abi.encode(currentState)), string(abi.encodePacked('This project is already ', currentState )));
        
        if(keccak256(abi.encode(newState)) == keccak256(abi.encode('opened'))){
            project.isFundable = true;
        } else if(keccak256(abi.encode(newState)) == keccak256(abi.encode('closed'))) {
            project.isFundable = false;
        }
        
        emit projectStateChanged(project.name, project.isFundable ? 'Project opened' : 'Project closed');
    }
    
    // Function modifiers
    modifier isAuthor(){
        require(project.authorAddress == msg.sender, "You must be the project author!");
        _;
    }
     
    modifier isNotAuthor() {
        require(project.authorAddress != msg.sender, "As author you can not fund your own project!");
        _;
    }
    
    modifier canFund(){
        require(project.isFundable == true, "This project is not available for funding!");
        _;
    }
    // ./Function modifiers
    
    function getGoal() public view returns(uint){
        return project.targetAmount;
    }
    
    function getFunds() public view returns(uint){
        return project.amountFunded;
    }
    
    function getStatus() public view returns(string memory){
        return project.isFundable ? 'Opened': 'Closed';
    }
}

Mi resultado al migrar todo a un struct type para el reto #5

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

contract CrowdFunding {
    
    struct Project {
        string name;
        string description;
        uint fundraisingGoal;
        address payable wallet;
        address owner;
        uint funds;
        uint status;
    }

    // Project Struct
    Project project;

    // Funds starts in zero.
    uint private initialFunds = 0;

    // Project Status:
    // status 0 = "Opened"
    // status 1 = "Closed"
    uint private initialState = 0;
    
    constructor(string memory _name, string memory _description, uint _fundraisingGoal) {
        project = Project(
            _name,
            _description,
            _fundraisingGoal,
            payable(msg.sender),
            msg.sender,
            initialFunds,
            initialState
        );
    }

    function fundProject() public payable ownerNotSendFunds {
        require(project.status == 0, "This project state is Closed!");
        require(msg.value > 0, "Funds can not be Zero!");

        project.wallet.transfer(msg.value);
        project.funds += msg.value;
        emit NewFundNotification(msg.sender, msg.value);
    }

    function changeProjectStatus(uint newStatus) public onlyOwnerModifyStates {
        require(project.status != newStatus, "Project has that state already, choose another!");
        project.status = newStatus;
        emit NewStatusChange(newStatus);
    }

    event NewFundNotification(
        address sender,
        uint fundAmount
    );
    
    event NewStatusChange(
        uint newStatus
    );


    modifier ownerNotSendFunds() {
        require(project.owner != msg.sender, "Owners shouldnt send funds to its own projects!");
        _;
    }

    modifier onlyOwnerModifyStates() {
         require(project.owner == msg.sender, "You must be the project owner!");
         _;
    }

    function getGoal() public view returns(uint) {
        return project.fundraisingGoal;
    }
    
    function getStatus() public view returns(uint) {
        return project.status;
    }
    
    function getFunds() public view returns (uint) {
        return project.funds;
    }
    
}

Reto de clase anterior

pragma solidity ^0.7.0;


contract KickstarterPoor {
        
    string name;
    string description;
   
    bool opened;
    uint256 goal;
    uint256 funds;
     address private owner;
    
    address payable creatorPayable;
    
   
    
    constructor(string memory _name, string memory _description, uint256 _goal) payable{
        
        name = _name;
        description = _description;
        owner = msg.sender;
        creatorPayable = payable(owner);
        goal = _goal;
        funds = 0;
        opened = true;
    }
   
    
    event newFunds(
        address sender,
        uint256 funds
        );
        
    event projectState(
        uint256 goal,
        uint256 funds,
        string state
        );
    
    
    function checkStatus () public view returns (bool){
        
    return opened;
    }
    
    function getFunds() public view returns (uint256){
        return funds;
    }
        
    
    
    modifier noFundOwner (){
          require(msg.sender != owner, "You can't donate to yourself, I'll call the police.");
        _;
    }
    
   modifier onlyOwner (){
        require(msg.sender == owner, "You are not admin, go away");
        _;
    }
    
     function FundProyect() public payable noFundOwner{
         require(opened, "The project is already closed");
         require(msg.value > 0 , "Funds > 0");
     
              creatorPayable.transfer(msg.value);
        funds += msg.value;
        emit newFunds(msg.sender,msg.value);
        
       
    }
    
    
    function changeProjectState(bool  newState) public  onlyOwner{
        require(opened != newState, "The same status cannot be reapplied");
        
        opened = newState;
        
        emit projectState(goal,funds,opened ? "Opened" : "Closed");
    }
    
    
}```

waaao los struc se usan en todos lados

Los struct types los veo como:

  • Objetos de JavaScript
  • Hashes / Objetos de Ruby
  • Diccionarios de Python.

Reto #5

struct Project {
        string public id;
        string public name;
        string public description;
        address payable public author;
        uint256 public state;
        uint256 public funds;
        uint256 public fundraisingGoal;
    }
    
    Project public project;