SESSIÓ 2 - UD2.2: FUNCIONS I MODIFICADORS - Solidity¶
Setmana 2 (27 abril - 3 maig) - 2 hores¶
FITXA TÈCNICA¶
| Dada | Valor |
|---|---|
| Unitat | UD2 - Smart Contracts |
| Tema | Funcions, visibilitat i modificadors |
| Durada | 2 hores |
| Nivell | Inicial-Intermedi |
| Eines | Remix IDE, MetaMask |
| Requisits | Sessió 1 completada |
OBJECTIUS D'APRENENTATGE¶
Al finalitzar aquesta sessió, seràs capaç de:
- ✅ Diferenciar i utilitzar correctament els modificadors de visibilitat (public, private, internal, external)
- ✅ Implementar modificadors d'estat (view, pure, payable)
- ✅ Crear i utilitzar modificadors personalitzats
- ✅ Implementar control d'accés amb
onlyOwner - ✅ Utilitzar constructors amb paràmetres
- ✅ Emetre i consultar events
- ✅ Aplicar les millores al contracte de calculadora
TEMPORITZACIÓ DE LA SESSIÓ¶
| Temps | Activitat | Metodologia |
|---|---|---|
| 0-10 min | Revisió sessió anterior | Q&A + dubtes |
| 10-30 min | Teoria: Visibilitat i modificadors | Exposició + exemples |
| 30-100 min | Pràctica guiada: Gestió d'usuaris | Codificació conjunta |
| 100-120 min | Exercici: Calculadora amb seguretat | Pràctica individual |
MATERIAL TEÒRIC¶
1. Modificadors de Visibilitat¶
Els modificadors de visibilitat determinen des d'on es pot cridar una funció o accedir a una variable.
Taula Comparativa:¶
| Visibilitat | Contracte | Derivats | Extern | Ús Típic |
|---|---|---|---|---|
public |
✅ | ✅ | ✅ | Funcions principals, getters |
private |
✅ | ❌ | ❌ | Lògica interna sensible |
internal |
✅ | ✅ | ❌ | Funcions per herència |
external |
❌ | ❌ | ✅ | Funcions per altres contracts |
Exemple Pràctic:¶
contract VisibilitatExemple {
uint256 public valorPublic; // Getter automàtic
uint256 private valorPrivate; // Només aquest contracte
uint256 internal valorInternal; // Aquest contracte + fills
// PUBLIC: Tothom pot cridar
function funcioPublica() public pure returns (string memory) {
return "Public - Tothom pot cridar";
}
// PRIVATE: Només aquest contracte
function funcioPrivate() private pure returns (string memory) {
return "Private - Només intern";
}
// INTERNAL: Aquest contracte i derivats
function funcioInternal() internal pure returns (string memory) {
return "Internal - Contracte i fills";
}
// EXTERNAL: Només des de fora (més eficient per arrays)
function funcioExterna() external pure returns (string memory) {
return "External - Només crida externa";
}
// Funció que crida funcions internes
function cridarInterna() public pure returns (string memory) {
return funcioInternal(); // ✅ Funciona
}
// Aquesta NO funcionaria:
// function cridarExterna() public pure returns (string memory) {
// return funcioExterna(); // ❌ Error: external function
// }
}
Nota important sobre external:
- Més eficient en gas per a paràmetres grans (arrays, strings)
- No es pot cridar des del mateix contracte directament
- Cal usar
this.funcioExterna()si es vol cridar internament
2. Modificadors d'Estat (State Mutability)¶
Indiquen com la funció interactua amb l'estat de la blockchain.
| Modificador | Llegeix Estat | Modifica Estat | Rep ETH | Gas | Exemple |
|---|---|---|---|---|---|
view |
✅ | ❌ | ❌ | Gratis | getBalance() |
pure |
❌ | ❌ | ❌ | Gratis | calculate(a, b) |
payable |
✅ | ✅ | ✅ | Paga | deposit() |
| (cap) | ✅ | ✅ | ❌ | Paga | transfer() |
Exemples Detallats:¶
contract ModificadorsEstat {
uint256 public valor = 100;
mapping(address => uint256) public saldos;
// VIEW: Llegeix estat, no modifica
function obtenirValor() public view returns (uint256) {
return valor; // ✅ Llegeix variable d'estat
}
// PURE: No llegeix ni modifica estat
function sumar(uint256 a, uint256 b) public pure returns (uint256) {
return a + b; // ✅ Només opera amb paràmetres
}
// PAYABLE: Pot rebre Ether
function dipositar() public payable {
require(msg.value > 0, "Ha d'enviar Ether");
saldos[msg.sender] += msg.value;
}
// SENSE MODIFICADOR: Pot modificar estat
function actualitzarValor(uint256 nouValor) public {
valor = nouValor; // ✅ Modifica variable d'estat
}
// Error comú:
// function incorrecte() public view returns (uint256) {
// valor = 200; // ❌ Error: view function cannot modify state
// return valor;
// }
}
3. Constructors amb Paràmetres¶
El constructor s'executa una sola vegada quan es desplega el contracte.
contract ContracteAmbConstructor {
address public propietari;
string public nom;
uint256 public dataCreacio;
uint256 public valorInicial;
// Constructor amb múltiples paràmetres
constructor(string memory _nom, uint256 _valorInicial) {
propietari = msg.sender; // Qui desplega
nom = _nom; // Paràmetre
dataCreacio = block.timestamp; // Timestamp actual
valorInicial = _valorInicial; // Paràmetre
}
// Aquest constructor NO es pot cridar després del desplegament
// function constructor(string memory _nom) public { // ❌ Error!
// nom = _nom;
// }
}
Quan es desplega:
Paràmetres: _nom = "El Meu Contracte", _valorInicial = 1000
Resultat:
- propietari: 0xYourAddress
- nom: "El Meu Contracte"
- dataCreacio: 1714000000 (timestamp)
- valorInicial: 1000
4. Modificadors Personalitzats¶
Els modificadors permeten reutilitzar codi de validació i control d'accés.
Sintaxi Bàsica:¶
modifier nomModificador() {
// Codi abans de la funció
require(condicio, "Missatge d'error");
_; // Executa la funció original
// Codi després de la funció (opcional)
}
Exemples Pràctics:¶
contract ModificadorsPersonalitzats {
address public propietari;
bool public actiu = true;
uint256 public comptador;
mapping(address => bool) public usuarisAutoritzats;
constructor() {
propietari = msg.sender;
usuarisAutoritzats[msg.sender] = true;
}
// 1. Control d'accés bàsic
modifier nomesPropietari() {
require(msg.sender == propietari, "No es el propietari");
_;
}
// 2. Contracte actiu
modifier contracteActiu() {
require(actiu, "Contracte no actiu");
_;
}
// 3. Usuari autoritzat
modifier usuariAutoritzat() {
require(usuarisAutoritzats[msg.sender], "Usuari no autoritzat");
_;
}
// 4. Límit de valor
modifier valorMaxim(uint256 maxim) {
require(comptador + 1 <= maxim, "Limit assolit");
_;
}
// 5. Validació de paràmetres
parametreValid(string memory text) {
require(bytes(text).length > 0, "Text buit");
require(bytes(text).length <= 100, "Text massa llarg");
_;
}
// Ús de modificadors
function destruir() public nomesPropietari {
selfdestruct(payable(propietari));
}
function afegirDada()
public
contracteActiu
usuariAutoritzat
valorMaxim(100)
{
comptador++;
}
function desactivar() public nomesPropietari {
actiu = false;
}
function afegirUsuari(address nouUsuari) public nomesPropietari {
usuarisAutoritzats[nouUsuari] = true;
}
// Múltiples modificadors en una funció
function operacioCritica(string memory dada)
public
nomesPropietari
contracteActiu
parametreValid(dada)
{
// Lògica crítica
comptador++;
}
}
Important:
- Els modificadors s'executen en ordre d'esquerra a dreta
_indica on s'executa la funció original- Es poden combinar múltiples modificadors
5. Events¶
Els events permeten registrar informació a la blockchain que es pot consultar des de fora del contracte.
contract EventsExemple {
address public propietari;
uint256 public comptador;
// Declaració d'events
event ContracteCreat(address indexed propietari, uint256 timestamp);
event ComptadorActualitzat(uint256 anticValor, uint256 nouValor);
event PropietariCanviat(address indexed antic, address indexed nou);
constructor() {
propietari = msg.sender;
emit ContracteCreat(msg.sender, block.timestamp);
}
function incrementar() public {
uint256 antic = comptador;
comptador++;
emit ComptadorActualitzat(antic, comptador);
}
function canviarPropietari(address nouPropietari) public {
require(msg.sender == propietari, "No es propietari");
address antic = propietari;
propietari = nouPropietari;
emit PropietariCanviat(antic, nouPropietari);
}
}
Indexed:
- Fins a 3 paràmetres poden ser
indexed - Permeten filtrar events eficientment
- Més costós en gas
Consulta d'events:
// Des de JavaScript (Ethers.js)
contract.on("ComptadorActualitzat", (antic, nou, event) => {
console.log(`Comptador: ${antic} → ${nou}`);
console.log(`Bloc: ${event.blockNumber}`);
});
PRÀCTICA GUIADA PAS A PAS¶
EXERCICI 1: Contracte de Gestió d'Usuaris¶
Objectiu: Crear un sistema de gestió d'usuaris amb control d'accés.
Pas 1: Crear el Fitxer¶
- A Remix IDE, crea un nou fitxer:
02_GestioUsuaris.sol - Copia l'estructura bàsica:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract GestioUsuaris {
// COMPLETAREM AQUEST CONTRACTE JUNTS
}
Pas 2: Afegir Variables d'Estat¶
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract GestioUsuaris {
// Estructura per a usuari
struct Usuari {
uint256 id;
string nom;
string email;
uint256 edat;
bool actiu;
uint256 dataRegistre;
}
// Variables d'estat
address public propietari;
uint256 public totalUsuaris;
uint256 public totalUsuarisActius;
// Mappings
mapping(uint256 => Usuari) public usuaris; // id → Usuari
mapping(address => uint256) public adresaId; // address → id
mapping(address => bool) public administradors; // address → bool
// Events
event UsuariRegistrat(uint256 indexed userId, address indexed adreca, string nom);
event UsuariActualitzat(uint256 indexed userId, string nom, bool actiu);
event UsuariEliminat(uint256 indexed userId);
event AdministradorAfegit(address indexed admin);
// ... continuarem
}
Pas 3: Constructor i Modificadors¶
contract GestioUsuaris {
// ... (variables anteriors)
constructor() {
propietari = msg.sender;
administradors[msg.sender] = true;
}
// Modificador: Només propietari
modifier nomesPropietari() {
require(msg.sender == propietari, "No es el propietari");
_;
}
// Modificador: Només administrador
modifier nomesAdministrador() {
require(administradors[msg.sender], "No es administrador");
_;
}
// Modificador: Usuari ha d'existir
modifier usuariExisteix(uint256 userId) {
require(userId > 0 && userId <= totalUsuaris, "Usuari no existeix");
_;
}
// Modificador: Contracte actiu
modifier contracteActiu() {
require(totalUsuaris < 1000, "Limit maxim d'usuaris assolit");
_;
}
}
Pas 4: Funcions de Registre¶
contract GestioUsuaris {
// ... (codi anterior)
// Funció per registrar nou usuari
function registrarUsuari(
string memory _nom,
string memory _email,
uint256 _edat
)
public
contracteActiu
returns (uint256)
{
// Validacions
require(bytes(_nom).length > 0, "Nom buit");
require(bytes(_email).length > 0, "Email buit");
require(_edat >= 18, "Ha de ser major d'edat");
require(adresaId[msg.sender] == 0, unicode"Ja estàs registrat");
// Crear nou usuari
totalUsuaris++;
uint256 nouId = totalUsuaris;
usuaris[nouId] = Usuari({
id: nouId,
nom: _nom,
email: _email,
edat: _edat,
actiu: true,
dataRegistre: block.timestamp
});
// Mapejar adreça a ID
adresaId[msg.sender] = nouId;
totalUsuarisActius++;
// Emitir event
emit UsuariRegistrat(nouId, msg.sender, _nom);
return nouId;
}
// Funció per obtenir les meves dades
function obtenirElMeuUsuari()
public
view
returns (
uint256 id,
string memory nom,
string memory email,
uint256 edat,
bool actiu,
uint256 dataRegistre
)
{
uint256 userId = adresaId[msg.sender];
require(userId > 0, unicode"No estàs registrat");
Usuari memory user = usuaris[userId];
return (
user.id,
user.nom,
user.email,
user.edat,
user.actiu,
user.dataRegistre
);
}
// Funció per obtenir usuari per ID (només admin)
function obtenirUsuariPerId(uint256 userId)
public
view
usuariExisteix(userId)
returns (
uint256 id,
string memory nom,
string memory email,
uint256 edat,
bool actiu
)
{
Usuari memory user = usuaris[userId];
return (
user.id,
user.nom,
user.email,
user.edat,
user.actiu
);
}
}
Pas 5: Funcions d'Actualització i Eliminació¶
contract GestioUsuaris {
// ... (codi anterior)
// Actualitzar les meves dades
function actualitzarPerfil(
string memory _nom,
string memory _email,
uint256 _edat
) public {
uint256 userId = adresaId[msg.sender];
require(userId > 0, unicode"No estàs registrat");
require(bytes(_nom).length > 0, "Nom buit");
require(bytes(_email).length > 0, "Email buit");
require(_edat >= 18, "Ha de ser major d'edat");
Usuari storage user = usuaris[userId];
user.nom = _nom;
user.email = _email;
user.edat = _edat;
emit UsuariActualitzat(userId, _nom, user.actiu);
}
// Desactivar compte (usuari)
function desactivarCompte() public {
uint256 userId = adresaId[msg.sender];
require(userId > 0, unicode"No estàs registrat");
Usuari storage user = usuaris[userId];
require(user.actiu, unicode"Ja està desactivat");
user.actiu = false;
totalUsuarisActius--;
emit UsuariActualitzat(userId, user.nom, false);
}
// Reactivar compte (usuari)
function reactivarCompte() public {
uint256 userId = adresaId[msg.sender];
require(userId > 0, unicode"No estàs registrat");
Usuari storage user = usuaris[userId];
require(!user.actiu, unicode"Ja està actiu");
user.actiu = true;
totalUsuarisActius++;
emit UsuariActualitzat(userId, user.nom, true);
}
// Eliminar usuari (només admin)
function eliminarUsuari(uint256 userId)
public
nomesAdministrador
usuariExisteix(userId)
{
Usuari storage user = usuaris[userId];
require(user.actiu, "Usuari ja inactiu");
user.actiu = false;
totalUsuarisActius--;
// Opcional: eliminar mapeig
// delete usuaris[userId];
emit UsuariEliminat(userId);
}
// Afegir administrador (només propietari)
function afegirAdministrador(address nouAdmin)
public
nomesPropietari
{
require(nouAdmin != address(0), "Adreça invalida");
require(!administradors[nouAdmin], "Ja es administrador");
administradors[nouAdmin] = true;
emit AdministradorAfegit(nouAdmin);
}
// Estadístiques
function obtenirEstadistiques()
public
view
returns (
uint256 total,
uint256 actius,
uint256 inactius
)
{
return (
totalUsuaris,
totalUsuarisActius,
totalUsuaris - totalUsuarisActius
);
}
}
Pas 6: Provar el Contracte¶
Seqüència de proves:
-
Desplegar contracte
Environment: Remix VM (Cancun) Account: Account 1 (propietari) -
Registrar primer usuari (Account 2)
Funció: registrarUsuari Paràmetres: - _nom: "Anna Martinez" - _email: "anna@email.com" - _edat: 28 Resultat esperat: userId = 1 -
Consultar dades
Funció: obtenirElMeuUsuari (des de Account 2) Resultat: - id: 1 - nom: "Anna Martinez" - email: "anna@email.com" - edat: 28 - actiu: true -
Registrar segon usuari (Account 3)
Paràmetres: - _nom: "Bernat Lopez" - _email: "bernat@email.com" - _edat: 35 Resultat: userId = 2 -
Consultar estadístiques
Funció: obtenirEstadistiques Resultat: - total: 2 - actius: 2 - inactius: 0 -
Actualitzar perfil (Account 2)
Funció: actualitzarPerfil Paràmetres: - _nom: "Anna Martinez Garcia" - _email: "anna.m@email.com" - _edat: 29 -
Desactivar compte (Account 2)
Funció: desactivarCompte Resultat: actiu = false -
Consultar estadístiques de nou
Resultat: - total: 2 - actius: 1 - inactius: 1 -
Afegir administrador (Account 1 - propietari)
Funció: afegirAdministrador Paràmetre: Account 3 (bernat@email.com) -
Eliminar usuari (Account 3 - ara admin)
Funció: eliminarUsuari Paràmetre: userId = 2 Resultat: usuari 2 eliminat
EXERCICI PROPOSAT: CALCULADORA AMB CONTROL D'ACCÉS¶
Enunciat:¶
Millora el contracte CalculadoraBasica de la sessió 1 afegint:
Requisits obligatoris:
-
Control d'accés:
- Afegir variable
propietari(address) - Constructor que guardi
msg.sendercom a propietari - Modificador
nomesPropietari
- Afegir variable
-
Límits d'operacions:
- Límit màxim de valor: 1,000,000
- Modificador
valorDinsLimit(uint256 valor)que validi - Missatge:
"Valor fora de limit"
-
Historial millorat:
- Estructura
Operacio:struct Operacio { uint256 id; address usuari; string tipus; // "suma", "resta", "multiplicacio" uint256 operand1; uint256 operand2; uint256 resultat; uint256 timestamp; } - Array d'operacions realitzades
- Mapping per consultar operacions per usuari
- Estructura
-
Events:
OperacioRealitzada(uint256 indexed operacioId, address indexed usuari, string tipus, uint256 resultat)LimitAssolit(address indexed usuari)
-
Funcions noves:
obtenirHistorialUsuari()→ retorna nombre d'operacions de qui cridaobtenirOperacio(uint256 id)→ retorna detalls d'una operacióresetejarComptador()→ només propietari, reseteja historialcanviarLimit(uint256 nouLimit)→ només propietari
Template per començar:¶
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract CalculadoraSegura {
uint256 public ultimResultat;
uint256 public totalOperacions;
address public propietari;
uint256 public limitMaxim;
struct Operacio {
uint256 id;
address usuari;
string tipus;
uint256 operand1;
uint256 operand2;
uint256 resultat;
uint256 timestamp;
}
Operacio[] public historial;
mapping(address => uint256[]) public operacionsPerUsuari;
event OperacioRealitzada(
uint256 indexed operacioId,
address indexed usuari,
string tipus,
uint256 resultat
);
event LimitAssolit(address indexed usuari);
constructor() {
propietari = msg.sender;
limitMaxim = 1000000;
}
// COMPLETA ELS MODIFICADORS I FUNCIONS
}
Solució:¶
Fes clic per veure la solució proposada
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract CalculadoraSegura {
uint256 public ultimResultat;
uint256 public totalOperacions;
address public propietari;
uint256 public limitMaxim;
struct Operacio {
uint256 id;
address usuari;
string tipus;
uint256 operand1;
uint256 operand2;
uint256 resultat;
uint256 timestamp;
}
Operacio[] public historial;
mapping(address => uint256[]) public operacionsPerUsuari;
event OperacioRealitzada(
uint256 indexed operacioId,
address indexed usuari,
string tipus,
uint256 resultat
);
event LimitAssolit(address indexed usuari);
constructor() {
propietari = msg.sender;
limitMaxim = 1000000;
}
modifier nomesPropietari() {
require(msg.sender == propietari, "No es el propietari");
_;
}
modifier valorDinsLimit(uint256 valor) {
require(valor <= limitMaxim, "Valor fora de limit");
_;
}
function sumar(uint256 a, uint256 b)
public
valorDinsLimit(a + b)
returns (uint256)
{
ultimResultat = a + b;
totalOperacions++;
_guardarOperacio("suma", a, b, ultimResultat);
return ultimResultat;
}
function restar(uint256 a, uint256 b)
public
valorDinsLimit(a)
returns (uint256)
{
require(a = b, "No es permeten resultats negatius");
ultimResultat = a - b;
totalOperacions++;
_guardarOperacio("resta", a, b, ultimResultat);
return ultimResultat;
}
function multiplicar(uint256 a, uint256 b)
public
valorDinsLimit(a * b)
returns (uint256)
{
ultimResultat = a * b;
totalOperacions++;
_guardarOperacio("multiplicacio", a, b, ultimResultat);
return ultimResultat;
}
function _guardarOperacio(
string memory tipus,
uint256 operand1,
uint256 operand2,
uint256 resultat)
internal {
uint256 operacioId = historial.length + 1;
historial.push(Operacio({
id: operacioId,
usuari: msg.sender,
tipus: tipus,
operand1: operand1,
operand2: operand2,
resultat: resultat,
timestamp: block.timestamp
}));
operacionsPerUsuari[msg.sender].push(operacioId - 1);
emit OperacioRealitzada(operacioId, msg.sender, tipus, resultat);
// Verificar si ha superat límit d'operacions
if (totalOperacions 100) {
emit LimitAssolit(msg.sender);
}
}
function obtenirHistorialUsuari() public view returns (uint256) {
return operacionsPerUsuari[msg.sender].length;
}
function obtenirOperacio(uint256 id)
public
view
returns (
uint256 operacioId,
address usuari,
string memory tipus,
uint256 operand1,
uint256 operand2,
uint256 resultat,
uint256 timestamp
)
{
require(id 0 && id <= historial.length, "Operacio no existeix");
Operacio memory op = historial[id - 1];
return (
op.id,
op.usuari,
op.tipus,
op.operand1,
op.operand2,
op.resultat,
op.timestamp
);
}
function resetejarComptador() public nomesPropietari {
delete historial;
totalOperacions = 0;
ultimResultat = 0;
}
function canviarLimit(uint256 nouLimit)
public
nomesPropietari
{
require(nouLimit 0, "Limit invalid");
limitMaxim = nouLimit;
}
function obtenirUltimResultat() public view returns (uint256) {
return ultimResultat;
}
function obtenirTotalOperacions() public view returns (uint256) {
return totalOperacions;
}
}
Proves recomanades:
sumar(100, 200) → 300
obtenirHistorialUsuari() → 1
multiplicar(50, 10) → 500
obtenirOperacio(1) → detalls de la suma
restar(1000, 300) → 700
obtenirTotalOperacions() → 3
sumar(500000, 600000) → Error: "Valor fora de limit"
canviarLimit(2000000) → només propietari
sumar(500000, 600000) → 1100000 (ara funciona)
resetejarComptador() → només propietari
obtenirTotalOperacions() → 0
EXERCICI EXTRA (Opcional)¶
Sistema de Votació amb Modificadors:
Crea un contracte que:
- Tingui modificadors per: votacioActiva, noHaVotat, usuariRegistrat
- Permeti registrar usuaris (només admin)
- Permeti iniciar/tancar votació (només admin)
- Permeti votar (usuaris registrats, votació activa, un cop)
- Registri events de cada vot
- Tingui límit de temps
MATERIALS DE SUPORT¶
Cheat Sheet de Modificadors:¶
// VISIBILITAT
public → Tothom (contracte, derivats, extern)
private → Només aquest contracte
internal → Contracte + contractes derivats
external → Només crida externa (més eficient)
// ESTAT
view → Llegeix estat, no modifica (gratis)
pure → No llegeix ni modifica (gratis)
payable → Pot rebre Ether
(cap) → Pot modificar estat (paga gas)
// MODIFICADORS PERSONALITZATS
modifier nomesPropietari() {
require(msg.sender == propietari, "Error");
_;
}
modifier valorMaxim(uint256 maxim) {
require(valor <= maxim, "Error");
_;
}
// ÚS
function funcio() public nomesPropietari valorMaxim(100) {
// Codi
}
Errors Comuns i Solucions:¶
| Error | Causa | Solució |
|---|---|---|
Function declared view but modifies state |
Funció view intenta modificar | Canvia a funció normal o elimina la modificació |
Modifier definition expected |
Sintaxi incorrecta de modifier | Assegura't d'usar modifier keyword i _ |
External function call failed |
Crida a external des de dins | Usa this.funcio() o canvia visibilitat |
Invalid modifier |
Modifier no definit | Defineix el modifier abans d'usar-lo |
Constructor defined incorrectly |
Constructor amb tipus de retorn | Elimina returns del constructor |
Bones Pràctiques:¶
✅ Fes:
- Usa private per defecte i public només quan calgui
- Implementa modificadors per reutilitzar validacions
- Emet events per a totes les accions importants
- Usa indexed en events per a filtres comuns
- Valida sempre les entrades amb require
❌ No facis:
- No facis tot public per comoditat
- No repeteixis codi de validació (usa modifiers)
- No oblidis els events
- No confiïs en dades externes sense validar
- No modifiquis estat en funcions view
Enllaços Útils:¶
- Solidity Modifiers: https://docs.soliditylang.org/en/latest/structure-of-a-contract.html#function-modifiers
- Visibilitat: https://solidity-by-example.org/visibility/
- Events: https://solidity-by-example.org/events/
- OpenZeppelin Access: https://docs.openzeppelin.com/contracts/4.x/access-control
QÜESTIONARI DE REPÀS¶
Respon abans de la propera sessió:
- Quina diferència hi ha entre
privateiinternal? - Per què
externalés més eficient per a arrays grans? - Què passa si una funció
viewintenta modificar una variable? - Què fa exactament
_dins d'un modifier? - Com es poden combinar múltiples modifiers en una funció?
- Per a què serveix
indexeden un event? - Quin modificador d'estat necessites per rebre Ether?
- Com cridaries una funció
externaldes del mateix contracte? - Quina és la diferència entre un constructor amb i sense paràmetres?
- Per què és important emetre events?
Solucions:
Fes clic per veure la solució proposada
privatenomés el contracte actual,internaltambé els contractes derivats- Perquè no copia les dades a memòria, les llegeix directament de calldata
- Donarà error de compilació: "Function declared view but modifies state"
- Indica on s'executarà la funció original que utilitza el modifier
- Separant-los amb espai:
function f() public modifier1 modifier2 { } - Permet filtrar events eficientment des de fora del contracte (màxim 3)
payable- Amb
this.nomFuncio()(crida externa) - Amb paràmetres permet inicialitzar variables al desplegar; sense paràmetres usa valors per defecte
- Perquè permeten rastrejar accions, actualitzar UI en temps real, i són essencials per a DApps
PREPARACIÓ PER LA SESSIÓ 3¶
Abans de la propera classe:
✅ Completa l'exercici de la calculadora amb seguretat
✅ Prova tots els modificadors al contracte de gestió d'usuaris
✅ Respon el qüestionari de repàs
✅ Porta dubtes sobre visibilitat i modifiers
Material a revisar: - Modificadors de visibilitat - Creació de modifiers personalitzats - Events i com consultar-los
Pròxima sessió: Estructures de dades avançades (structs, mappings, arrays)
CONSELLS¶
Per dominar els modificadors:¶
-
Practica la reutilització:
- Si reps codi, probablement necessites un modifier
- Exemple: múltiples funcions amb
require(msg.sender == propietari)→ creanomesPropietari
-
Entén l'ordre d'execució:
function f() public modifierA modifierB { // 1. Codi de modifierA (abans de _) // 2. Codi de modifierB (abans de _) // 3. Codi de f() // 4. Codi de modifierB (després de _) // 5. Codi de modifierA (després de _) } -
Depura amb events:
- Afegeix events als modifiers per veure quan s'executen
- Exemple:
event ModifierExecutat(string modifierName);
Per evitar errors comuns:¶
- ✅ Sempre valida les entrades
- ✅ Usa
indexeden events que filtraràs sovint - ✅ Prova tots els camins d'execució
- ✅ Revisa els permisos de cada funció
✅ CHECKLIST FINAL DE LA SESSIÓ 2:
- Entenc la diferència entre public, private, internal, external
- Puc crear modificadors personalitzats
- Sé quan usar view, pure o payable
- He completat el contracte de gestió d'usuaris
- He millorat la calculadora amb control d'accés
- He emès events correctament
- He respost el qüestionari de repàs
