Solidity implementa un tipo de función especial denominada Modificadores que nos permiten ejecutar una pieza de código antes o después del comportamiento de la propia función.
Comportamiento de una función
Los usos más frecuentes de los modificadores suelen ser la validación de datos o la restricción de acceso a una función si el usuario no tiene permisos. Dichas validaciones puedesn realizarse con modificadores que además permiten ser reutilizadas.
Estos nos permiten hacer validaciones antes de ejecutar las funciones. De esta forma, podemos evitar comportamientos inesperados o que alguien sin autorización ejecute la función.
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract FunctionModifier { address public owner;constructor(){// Guardamos la información del dueño del contrato para validar al mismo owner = msg.sender;}// Modificador para validar que la llamada la realiza el dueño del contrato modifier onlyOwner(){require(msg.sender == owner,"No eres el owner"); _;}// Solo el dueño del proyecto puede cambiar al mismo function changeOwner(address _newOwner) public onlyOwner { owner = _newOwner;}}
La sintaxis de un modificador es sencilla, utilizando la palabra reservada modifier, declaramos la función y dentro del mismo utilizamos un require para realizar una validación y un _ para indicarle al compilador de Solidity que continúe ejecutando el resto de la función si la condición se cumplió correctamente.
En el caso de que la condición no se cumpla y el modificador rechace la transacción, el require realizará un revert para volver atrás todos los cambios de estado del contrato por nosotros y que no tengamos que preocuparnos. Las operaciones en Solidity son atómicas, lo que quiere decir que se ejecuta correctamente cada una de las instrucciones o no se ejecuta ninguna.
Finalmente, una función puede implementar el modificador en la declaración de la misma. A lo igual que indicamos que una función es public o pure, también le implementamos el nombre del modificador que utilizará.
function changeOwner(address _newOwner) public onlyOwner {}
La lógica dentro del modificador puede ser del nivel de complejidad que necesitemos, usando condicionales u otros flujos de control. Con esta característica de Solidity, ya estás listo o lista para desarrollar contratos con permisos y validaciones de datos para que el flujo del mismo sea el esperado.
Contribución creada por:Luis Enrique Herrera y Kevin Fiorentino (Platzi Contributors).
Yo estaba haciendo cosas extrañas con el if para evitar eso que alguien mas cambiara el nombre, debi terminar la clase primero XD
jajajajajajaja, tranqui a todos nos pasa
jajaja x2
Modificadores de funciones
Nos permiten hacer validaciones antes de ejecutar nuestra función, de esta forma podemos evitar comportamientos inesperados o que la función sea ejecutada por alguien que no tiene permisos de hacerlo.
Gracias por el resumen
El código está genial, pero si creo que deberían ponerle comentarios, no sé qué tan bueno sea esto para los Smart Contracts.
El codigo es autoexplicativo 🤔
Siempre me ha parecido una buena práctica dejar un comentario sobre cada línea que se desarrolla. Sobre todo si el código luego va a ser visto por otros. Genera mucha más claridad.
Ahora con modifier .. muy chevere como fluye todo
// SPDX-License-Identifier: GPL-3.0// enmarca las versiones del compilador que soporta el smart contractpragma solidity >=0.7.0<0.9.0;// nombre del contrato contract FondosProyecto{// variables de estado del contrato// se etablecen a publicas para que se puedan ver int public idProyecto; string public nameProyecto; uint256 public objetivoFondos; bool private recibeFondos;// esta variable es address payable por que maneja la cartera que vamos a recibir los fondos address payable public autor;// variable para almacenar el proietario de la wallet address private owner; uint256 public fondos;// constructor que permite registrar la informacion del proyecto y su objetivo constructor(int _idProyecto, string memory _nameProyecto, uint256 _objetivoFondos){ idProyecto = _idProyecto; nameProyecto=_nameProyecto; objetivoFondos = _objetivoFondos; autor =payable(msg.sender);// se inicializa con la cartera actual recibeFondos =true;// es verdareo cuando inicia a re¿cibir fondos//se inicializa la cartera del propuetario owner = msg.sender;}// esta funcion permite realizar la transaccion de una carte a la cartera propia // no sin antes verificar si no se ha legado al tope del objetivo de los fondosfunctionfundProyect()public payable {// si aun recibe fondos if(recibeFondos){ autor.transfer(msg.value); fondos += msg.value;}// verifica si cumplio con el objetivo para no recibir mas fondoschangeFundProyect();// cambia el estado de la variable a falso}// modifier no permite abonar fondos por el propietario del proyecto modifier notOnlyOwnerPay(){require(autor != owner,"El propietario no puede abonar fondos al proyecto");//la funcion es insertada donde aparece este simbolo _ _;}// cambia el estado de la variable si los fondos recibidos son superiores a los objetivofunctionchangeFundProyect()public payable notOnlyOwnerPay {if(fondos > objetivoFondos){ recibeFondos =false;}}// funcion que retorna el estado de la variable si recibe fondosfunctiongetRecibeFondos()public view returns(bool){return recibeFondos;}// restringe a que solo el propietario de la Wallet permita cambiar un estado modifier onlyOwner(){require(msg.sender== owner,"Solo el propietario pude realizar estos cambios");//la funcion es insertada donde aparece este simbolo _ _;}// aplicamos la funcion modiifer para restringir el cambio del la ariable recibe-fondos functionchangeRecibeFondos()public onlyOwner {if(recibeFondos){ recibeFondos =false;}else{ recibeFondos =true;}}}
El constructor se ejecuta únicamente por el autor del contrato y ya luego no cumple otra función?
Así es, el constructor solo nos va a servir para desplegar nuestro contrato asignándole valores iniciales a las variables de estado, luego de desplegar el contrato nunca lo vamos a volver a usar
Hola, para comentarles que yo puse el mensaje del modifier en español y el compilador no me aceptó la ñ, uno creería que al ser un string no hay problema pero no, da error de "invalid character".
Espero que a alguien le sirva.
segun entiendo, eso sucede porque modifier es una palabra reservada dentro del lenguaje, cualquier cambio en alguna letra genera un error.
Estaba medio loco en la anterior clase, pero ya voy avanzando y entendiendo .. me esta gustandoo ..!
aqui mi version
// SPDX-License-Identifier: GPL-3.0// enmarca las versiones del compilador que soporta el smart contractpragma solidity >=0.7.0<0.9.0;// nombre del contrato contract FondosProyecto{// variables de estado del contrato// se etablecen a publicas para que se puedan ver int public idProyecto; string public nameProyecto; uint256 public objetivoFondos; bool private recibeFondos;// esta variable es address payable por que maneja la cartera que vamos a recibir los fondos address payable public autor; uint256 public fondos;// constructor que permite registrar la informacion del proyecto y su objetivo constructor(int _idProyecto, string memory _nameProyecto, uint256 _objetivoFondos){ idProyecto = _idProyecto; nameProyecto=_nameProyecto; objetivoFondos = _objetivoFondos; autor =payable(msg.sender);// se inicializa con la cartera actual recibeFondos =true;// es verdareo cuando inicia a re¿cibir fondos}// esta funcion permite realizar la transaccion de una carte a la cartera propia // no sin antes verificar si no se ha legado al tope del objetivo de los fondosfunctionfundProyect()public payable {// si aun recibe fondos if(recibeFondos){ autor.transfer(msg.value); fondos += msg.value;}// verifica si cumplio con el objetivo para no recibir mas fondoschangeFundProyect();// cambia el estado de la variable a falso}// cambia el estado de la variable si los fondos recibidos son superiores a los objetivofunctionchangeFundProyect()public payable {if(fondos > objetivoFondos){ recibeFondos =false;}}// funcion que retorna el estado de la variable si recibe fondosfunctiongetRecibeFondos()public view returns(bool){return recibeFondos;}}
Osea como tal el Owner va a ser la dirección que esta activa cuando le damos Deploy?
Así es, como puedes ver en el constructor asignamos como valor inicial de la variable de estado owner, la dirección de quién esta desplegando el contrato usando la variable msg.sender
Este es el verdadero curso de Introducción a Solidity, no diré mas
Me ha costado un poco entener todo y tuve que corregir errores pero lo logré y me alegró el día jajajaja. Aquí les dejo el código:
// SPDX-License-Identifier: GPL-3.0pragma solidity >=0.7.0<0.9.0;/**
* @title Storage
* @dev Store & retrieve value in a variable
*/contract platziProject { string public id; string public name; string public description; address payable public author; string public state ="Opened"; uint256 public funds; uint256 public fundraisingGoal;constructor(string memory _id, string memory _name, string memory _description, uint256 _fundraisingGoal){ id = _id; name = _name; description = _description; fundraisingGoal = _fundraisingGoal; author =payable(msg.sender);} modifier onlyOwner(){require( msg.sender== author,"Only owner can change the project state"); _;} modifier exceptOwner(){require( msg.sender!= author,"Owner can't send funds"); _;}functionfundProject()public payable exceptOwner{ author.transfer(msg.value); funds += msg.value;}functionchangeProjectState(string calldata newState)public onlyOwner{ state = newState;}}
Convalidacion del dueño(owner)
El constructor sólo se ejecuta 1 vez , y es al momento de crearlo por eso al colocar (owner=msg.sender) , solo se guarda nuestra dirección de wallet como “owner” que es nuestra direccion , el modifiere convalidara que la direccion de otras wallets(msg.sender) no se igual a la original “owner”.
Asi evita que pueda ser cambiada.
Llamar la funcion modifiere onlyOwner para evitar modificaciones externas.
Muchas gracias, justo esto me aclaro mucho respecto a la lógica
Solución reto 2
Notar que se puede agregar mas de un modifier por función:
// SPDX-License-Identifier: MITpragma solidity ^0.5.0;contract Project{ string public name; bool public isActive; address payable public owner; uint public founds; uint public goal;constructor(string memory _name, uint _goal)public{ name = _name; goal = _goal; isActive =true; owner = msg.sender;} modifier onlyOwner(){require(owner == msg.sender,"You are not the project owner"); _;} modifier notOwner(){require(owner != msg.sender,"You cannot transfer to your own project"); _;} modifier onlyWhenActive(){require(isActive,"This project is not active."); _;}functionfundProject()public payable notOwner onlyWhenActive { owner.transfer(msg.value); founds += msg.value;}functionchangeProjectState()public onlyOwner { isActive =!isActive;}}
los modificadores pueden ser interpretados como una interfaces?
Compañeros, me gustaría que alguien pudiera darme otro ejemplo en el que se puede poner en práctica un modifier en un smart conrtact. Se los agradecería muchísimo
Tiene muchos casos de uso el function modifier, porque permite hacer una validación antes de entrar a el código de la función, por ejemplo, imagina que quieres restringir que no se pueda llamar la función si no hay un valor de ether enviado o que quieras restringir ciertas funciones a diferentes roles, estos roles pueden ser validados en un function modifier
el mensaje que coloco en el modifier, cuando lo coloco en español, no me compila, por que????
:thinking: en realidad puedes poner cualquier mensaje no importa el idioma, quizás el error sea distinto, puedes compartirnos tu código ?
Al parecer no se aceptan caracteres que no estén en el abecedario anglosajón, como la ñ, las letras con acento o los emojis.
¿No se podía desde el principio hacer payable el addres del autor? o xq es necesario hacerla payable recién cuando está dentro del constructor?
Hola Sergio es necesario porque el tipo de variable de msg.sender es de tipo address, para que podamos asignarla a nuestra variable autor, que es de tipo address payable, necesitamos convertir msg.sender de tipo adrress a adrress payable
Se puede asignar más de un mdifier por funcion?
Puedo estructurar un poco más el proyecto creando los modifiers en un archivo separado e importarlo posteriormente en el archivo que requiere los modificadores?
Lo que puedes hacer es llamar contratos dentro de otros contratos, con la visibilidad correcta (public, internal) puedes usar modifiers que estén definidos en otro contrato.
Sin embargo, existen otros conceptos más avanzados de programación orientada a objetos, que permiten agrupar características similares para varias clases (contratos) y está seria la forma más correcta de hacerlo
He intentado agregar una validación para evitar que se transfieran fondos si el estado del proyecto no es "Active"... pero me sale el siguiente error:
![error comparacion de strings.png
.
![error comparacion de strings 2.png