Ir al contenido principal
Change page

Anatomía de los contratos inteligentes

Última actualización de la página: 2 de diciembre de 2025

Un contrato inteligente es un programa que se ejecuta en una dirección en Ethereum. Están formados por datos y funciones, que se pueden ejecutar al recibir una transacción. A continuación encontrarás una visión general de lo que compone un contrato inteligente.

Requisitos previos

Asegúrese de haber leído primero sobre los contratos inteligentes. Este documento asume que ya estás familiarizado con lenguajes de programación como JavaScript o Python.

Datos

Cualquier dato del contrato debe asignarse a una ubicación: ya sea a storage o memory. Es costoso modificar el almacenamiento en un contrato inteligente, por lo que debes considerar dónde deben ubicarse sus datos.

Almacenamiento

Los datos persistentes se denominan almacenamiento y se representan por variables de estado. Estos valores se almacenan permanentemente en la blockchain. Necesitas declarar el tipo de dato para que el contrato pueda llevar un seguimiento de la cantidad de almacenamiento en la blockchain que se necesitará cuando compile.

1// Ejemplo de Solidity
2contract SimpleStorage {
3 uint storedData; // Variable de estado
4 // ...
5}
1# ejemplo de Vyper
2storedData: int128

Si ya has utilizado lenguajes de programación orientados a objetos, probablemente estarás familiarizado con la mayoría de tipos de datos. Sin embargo, address debería ser nuevo para usted si es nuevo en el desarrollo de Ethereum.

Un tipo address puede contener una dirección de Ethereum que equivale a 20 bytes o 160 bits. Devuelve en notación hexadecimal con un 0x al inicio.

Otros tipos de variables incluyen:

  • booleano
  • entero
  • números de punto fijo
  • matrices de bytes de punto fijo
  • matrices de bytes de tamaño dinámico
  • literales racionales y enteros
  • literales de cadena
  • literales hexadecimales
  • enums

Para más explicación, echa un vistazo a la documentación:

Memoria

Los valores que sólo se almacenan durante la vida útil de la ejecución de una función de contrato se llaman variables de memoria. Dado que estos no se almacenan permanentemente en la blockchain, son mucho más baratos de usar.

Obtenga más información sobre cómo la EVM almacena los datos (almacenamiento, memoria y pila) en los documentos de Solidityopens in a new tab.

Variables de entorno

Además de las variables que se definen en su contrato, hay algunas variables globales especiales. Se utilizan principalmente para proporcionar información acerca de la cadena de bloques o la transacción actual.

Ejemplos:

PropiedadVariable de estadoDescripción
block.timestampuint256Marca de tiempo del bloque actual
msg.senderdirecciónRemitente del mensaje (llamada actual)

Funciones

De una forma simplista, las funciones pueden obtener información o establecer información en respuesta a las transacciones entrantes.

Existen dos tipos de llamadas de funciones:

  • internal: estas no crean una llamada a la EVM
    • Solo se puede acceder a las funciones y variables de estado internas desde dentro (es decir, desde el contrato actual o los contratos que se deriven de él)
  • external: estas sí crean una llamada a la EVM
    • Las funciones externas forman parte de la interfaz del contrato, lo que significa que se pueden llamar desde otros contratos y a través de transacciones. Una función externa f no se puede llamar internamente (es decir, f() no funciona, pero this.f() sí).

También pueden ser public o private

  • Las funciones public se pueden llamar internamente desde el contrato o externamente a través de mensajes
  • Las funciones private solo son visibles para el contrato en el que se definen y no para los contratos derivados

Tanto las funciones como las variables de estado pueden hacerse públicas o privadas.

Aquí se ejemplifica una función para actualizar una variable de estado en un contrato:

1// ejemplo de Solidity
2function update_name(string value) public {
3 dapp_name = value;
4}
  • El parámetro value de tipo string se pasa a la función: update_name
  • Se declara como public, lo que significa que cualquiera puede acceder a ella
  • No se declara como view, por lo que puede modificar el estado del contrato

Funciones de vista

Estas funciones no modifican el estado de los datos del contrato. Ejemplos comunes son las funciones "getter", que se pueden utilizar para recibir el saldo o balance de un usuario, por ejemplo.

1// Ejemplo de Solidity
2function balanceOf(address _owner) public view returns (uint256 _balance) {
3 return ownerPizzaCount[_owner];
4}
1dappName: public(string)
2
3@view
4@public
5def readName() -> string:
6 return dappName

Qué se considera modificar un estado:

  1. Escribir a variables de estado.
  2. Emisión de eventosopens in a new tab.
  3. Creación de otros contratosopens in a new tab.
  4. Uso de selfdestruct.
  5. Enviae ethers mediante llamadas.
  6. Llamar a cualquier función no marcada como view o pure.
  7. Usar llamadas de bajo nivel.
  8. Utilizando un ensamblaje en línea que contiene ciertos códigos de operador.

Funciones constructoras

Las funciones constructor solo se ejecutan una vez cuando el contrato se implementa por primera vez. Al igual que constructor en muchos lenguajes de programación basados en clases, estas funciones a menudo inicializan las variables de estado con sus valores especificados.

1// Ejemplo de Solidity
2// Inicializa los datos del contrato, estableciendo el `owner`
3// a la dirección del creador del contrato.
4constructor() public {
5 // Todos los contratos inteligentes dependen de transacciones externas para activar sus funciones.
6 // `msg` es una variable global que incluye datos relevantes sobre la transacción dada,
7 // como la dirección del remitente y el valor de ETH incluido en la transacción.
8 // Más información: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
9 owner = msg.sender;
10}
Mostrar todo
1# Ejemplo en Vyper
2
3@external
4def __init__(_beneficiary: address, _bidding_time: uint256):
5 self.beneficiary = _beneficiary
6 self.auctionStart = block.timestamp
7 self.auctionEnd = self.auctionStart + _bidding_time

Funciones incorporadas

Además de las variables y funciones que define en su contrato, hay algunas funciones especiales integradas. El ejemplo más obvio es:

  • address.send() – Solidity
  • send(address) – Vyper

Esto permite que los contratos envíen ETH a otras cuentas.

Escribir funciones

Su función necesita:

  • parámetro de la variable y tipo de variable (si acepta parámetros)
  • declaraciónde variable interna/externa
  • declaración de variable de tipo pure/view/payable
  • devuelve el tipo (valor, en caso de devolución)
1pragma solidity >=0.4.0 <=0.6.0;
2
3contract ExampleDapp {
4 string dapp_name; // variable de estado
5
6 // Se llama cuando el contrato se implementa e inicializa el valor
7 constructor() public {
8 dapp_name = "Mi dapp de ejemplo";
9 }
10
11 // Función Get
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // Función Set
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
Mostrar todo

Un contrato completo podría verse así. Aquí la función constructor proporciona un valor inicial para la variable dapp_name.

Eventos y registros

Los eventos permiten que su contrato inteligente se comunique con su interfaz o frontend, u otras aplicaciones de suscripción. Una vez que una transacción es validada y se agrega a un bloque, los contratos inteligentes pueden emitir eventos y registrar información, que la frontend puede procesar y utilizar.

Ejemplos anotados

Estos son algunos ejemplos escritos en Solidity. Si le gustaría jugar con el código, puede interactuar con ellos en Remixopens in a new tab.

Hola, mundo

1// Especifica la versión de Solidity, usando un versionado semántico.
2// Más información: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// Define un contrato llamado `HelloWorld`.
6// Un contrato es una colección de funciones y datos (su estado).
7// Una vez implementado, un contrato reside en una dirección específica de la cadena de bloques de Ethereum.
8// Más información: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
9contract HelloWorld {
10
11 // Declara una variable de estado `message` de tipo `string`.
12 // Las variables de estado son variables cuyos valores se almacenan permanentemente en el almacenamiento del contrato.
13 // La palabra clave `public` hace que las variables sean accesibles desde fuera de un contrato
14 // y crea una función a la que otros contratos o clientes pueden llamar para acceder al valor.
15 string public message;
16
17 // Al igual que en muchos lenguajes de programación orientados a objetos basados en clases, un constructor es
18 // una función especial que solo se ejecuta en la creación del contrato.
19 // Los constructores se utilizan para inicializar los datos del contrato.
20 // Más información: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
21 constructor(string memory initMessage) public {
22 // Acepta un argumento de cadena `initMessage` y establece el valor
23 // en la variable de almacenamiento `message` del contrato.
24 message = initMessage;
25 }
26
27 // Una función pública que acepta un argumento de cadena
28 // y actualiza la variable de almacenamiento `message`.
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
Mostrar todo

Token

1pragma solidity ^0.5.10;
2
3contract Token {
4 // Una `address` es comparable a una dirección de correo electrónico; se utiliza para identificar una cuenta en Ethereum.
5 // Las direcciones pueden representar un contrato inteligente o cuentas externas (de usuario).
6 // Más información: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // Un `mapping` es, esencialmente, una estructura de datos de tabla de hash.
10 // Este `mapping` asigna un número entero sin signo (el saldo del token) a una dirección (el poseedor del token).
11 // Más información: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // Los eventos permiten registrar la actividad en la cadena de bloques.
15 // Los clientes de Ethereum pueden escuchar eventos para reaccionar a los cambios de estado del contrato.
16 // Más información: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
17 event Transfer(address from, address to, uint amount);
18
19 // Inicializa los datos del contrato, estableciendo el `owner`
20 // a la dirección del creador del contrato.
21 constructor() public {
22 // Todos los contratos inteligentes dependen de transacciones externas para activar sus funciones.
23 // `msg` es una variable global que incluye datos relevantes sobre la transacción dada,
24 // como la dirección del remitente y el valor de ETH incluido en la transacción.
25 // Más información: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
26 owner = msg.sender;
27 }
28
29 // Crea una cantidad de nuevos tokens y los envía a una dirección.
30 function mint(address receiver, uint amount) public {
31 // `require` es una estructura de control que se utiliza para aplicar ciertas condiciones.
32 // Si una declaración `require` se evalúa como `false`, se activa una excepción,
33 // que revierte todos los cambios realizados en el estado durante la llamada actual.
34 // Más información: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
35
36 // Solo el propietario del contrato puede llamar a esta función
37 require(msg.sender == owner, "Usted no es el propietario.");
38
39 // Aplica una cantidad máxima de tokens
40 require(amount < 1e60, "Se superó la emisión máxima");
41
42 // Aumenta el saldo de `receiver` en `amount`
43 balances[receiver] += amount;
44 }
45
46 // Envía una cantidad de tokens existentes desde cualquier llamador a una dirección.
47 function transfer(address receiver, uint amount) public {
48 // El remitente debe tener suficientes tokens para enviar
49 require(amount <= balances[msg.sender], "Saldo insuficiente.");
50
51 // Ajusta los saldos de tokens de las dos direcciones
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // Emite el evento definido anteriormente
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
Mostrar todo

Activo digital único

1pragma solidity ^0.5.10;
2
3// Importa símbolos de otros archivos en el contrato actual.
4// En este caso, una serie de contratos de ayuda de OpenZeppelin.
5// Más información: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files
6
7import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";
10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";
11
12// La palabra clave `is` se utiliza para heredar funciones y palabras clave de contratos externos.
13// En este caso, `CryptoPizza` hereda de los contratos `IERC721` y `ERC165`.
14// Más información: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
15contract CryptoPizza is IERC721, ERC165 {
16 // Utiliza la librería SafeMath de OpenZeppelin para realizar operaciones aritméticas de forma segura.
17 // Más información: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath
18 using SafeMath for uint256;
19
20 // Las variables de estado constantes en Solidity son similares a las de otros lenguajes,
21 // pero debe asignarlas desde una expresión que sea constante en tiempo de compilación.
22 // Más información: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables
23 uint256 constant dnaDigits = 10;
24 uint256 constant dnaModulus = 10 ** dnaDigits;
25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
26
27 // Los tipos de estructura le permiten definir su propio tipo
28 // Más información: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // Crea una matriz vacía de estructuras de Pizza
35 Pizza[] public pizzas;
36
37 // Mapeo del ID de la pizza a la dirección de su propietario
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // Mapeo de la dirección del propietario al número de tokens que posee
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // Mapeo del ID del token a la dirección aprobada
44 mapping(uint256 => address) pizzaApprovals;
45
46 // Puede anidar mapeos, este ejemplo mapea al propietario a las aprobaciones del operador
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // Función interna para crear una Pizza aleatoria a partir de una cadena (nombre) y un ADN
50 function _createPizza(string memory _name, uint256 _dna)
51 // La palabra clave `internal` significa que esta función solo es visible
52 // dentro de este contrato y de los contratos que derivan de este
53 // Más información: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
54 internal
55 // `isUnique` es un modificador de función que comprueba si la pizza ya existe
56 // Más información: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // Añade una pizza a la matriz de pizzas y obtiene el ID
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // Comprueba que el propietario de la pizza es el mismo que el usuario actual
63 // Más información: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64
65 // tenga en cuenta que address(0) es la dirección cero,
66 // lo que indica que pizza[id] aún no está asignada a un usuario en particular.
67
68 assert(pizzaToOwner[id] == address(0));
69
70 // Mapea la pizza al propietario
71 pizzaToOwner[id] = msg.sender;
72 ownerPizzaCount[msg.sender] = SafeMath.add(
73 ownerPizzaCount[msg.sender],
74 1
75 );
76 }
77
78 // Crea una pizza aleatoria a partir de una cadena (nombre)
79 function createRandomPizza(string memory _name) public {
80 uint256 randDna = generateRandomDna(_name, msg.sender);
81 _createPizza(_name, randDna);
82 }
83
84 // Genera un ADN aleatorio a partir de una cadena (nombre) y la dirección del propietario (creador)
85 function generateRandomDna(string memory _str, address _owner)
86 public
87 // Las funciones marcadas como `pure` prometen no leer ni modificar el estado
88 // Más información: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
89 pure
90 returns (uint256)
91 {
92 // Genera un uint aleatorio a partir de una cadena (nombre) + dirección (propietario)
93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
94 uint256(_owner);
95 rand = rand % dnaModulus;
96 return rand;
97 }
98
99 // Devuelve una matriz de pizzas encontradas por el propietario
100 function getPizzasByOwner(address _owner)
101 public
102 // Las funciones marcadas como `view` prometen no modificar el estado
103 // Más información: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
104 view
105 returns (uint256[] memory)
106 {
107 // Utiliza la ubicación de almacenamiento `memory` para almacenar valores solo durante
108 // el ciclo de vida de esta llamada de función.
109 // Más información: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
111 uint256 counter = 0;
112 for (uint256 i = 0; i < pizzas.length; i++) {
113 if (pizzaToOwner[i] == _owner) {
114 result[counter] = i;
115 counter++;
116 }
117 }
118 return result;
119 }
120
121 // Transfiere la pizza y la propiedad a otra dirección
122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
123 require(_from != address(0) && _to != address(0), "Dirección no válida.");
124 require(_exists(_pizzaId), "La pizza no existe.");
125 require(_from != _to, "No se puede transferir a la misma dirección.");
126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "La dirección no está aprobada.");
127
128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
130 pizzaToOwner[_pizzaId] = _to;
131
132 // Emite el evento definido en el contrato IERC721 importado
133 emit Transfer(_from, _to, _pizzaId);
134 _clearApproval(_to, _pizzaId);
135 }
136
137 /**
138 * Transfiere de forma segura la propiedad de un ID de token determinado a otra dirección
139 * Si la dirección de destino es un contrato, debe implementar `onERC721Received`,
140 * que se llama en una transferencia segura, y devuelve el valor mágico
141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
142 * de lo contrario, la transferencia se revierte.
143 */
144 function safeTransferFrom(address from, address to, uint256 pizzaId)
145 public
146 {
147 // solium-disable-next-line arg-overflow
148 this.safeTransferFrom(from, to, pizzaId, "");
149 }
150
151 /**
152 * Transfiere de forma segura la propiedad de un ID de token determinado a otra dirección
153 * Si la dirección de destino es un contrato, debe implementar `onERC721Received`,
154 * que se llama en una transferencia segura, y devuelve el valor mágico
155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
156 * de lo contrario, la transferencia se revierte.
157 */
158 function safeTransferFrom(
159 address from,
160 address to,
161 uint256 pizzaId,
162 bytes memory _data
163 ) public {
164 this.transferFrom(from, to, pizzaId);
165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Debe implementar onERC721Received.");
166 }
167
168 /**
169 * Función interna para invocar `onERC721Received` en una dirección de destino
170 * La llamada no se ejecuta si la dirección de destino no es un contrato
171 */
172 function _checkOnERC721Received(
173 address from,
174 address to,
175 uint256 pizzaId,
176 bytes memory _data
177 ) internal returns (bool) {
178 if (!isContract(to)) {
179 return true;
180 }
181
182 bytes4 retval = IERC721Receiver(to).onERC721Received(
183 msg.sender,
184 from,
185 pizzaId,
186 _data
187 );
188 return (retval == _ERC721_RECEIVED);
189 }
190
191 // Quema una pizza: destruye el token por completo
192 // El modificador de función `external` significa que esta función forma
193 // parte de la interfaz del contrato y otros contratos pueden llamarla
194 function burn(uint256 _pizzaId) external {
195 require(msg.sender != address(0), "Dirección no válida.");
196 require(_exists(_pizzaId), "La pizza no existe.");
197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "La dirección no está aprobada.");
198
199 ownerPizzaCount[msg.sender] = SafeMath.sub(
200 ownerPizzaCount[msg.sender],
201 1
202 );
203 pizzaToOwner[_pizzaId] = address(0);
204 }
205
206 // Devuelve el recuento de pizzas por dirección
207 function balanceOf(address _owner) public view returns (uint256 _balance) {
208 return ownerPizzaCount[_owner];
209 }
210
211 // Devuelve el propietario de la pizza encontrada por ID
212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
213 address owner = pizzaToOwner[_pizzaId];
214 require(owner != address(0), "ID de pizza no válido.");
215 return owner;
216 }
217
218 // Aprueba a otra dirección para transferir la propiedad de la pizza
219 function approve(address _to, uint256 _pizzaId) public {
220 require(msg.sender == pizzaToOwner[_pizzaId], "Debe ser el propietario de la pizza.");
221 pizzaApprovals[_pizzaId] = _to;
222 emit Approval(msg.sender, _to, _pizzaId);
223 }
224
225 // Devuelve la dirección aprobada para una pizza específica
226 function getApproved(uint256 _pizzaId)
227 public
228 view
229 returns (address operator)
230 {
231 require(_exists(_pizzaId), "La pizza no existe.");
232 return pizzaApprovals[_pizzaId];
233 }
234
235 /**
236 * Función privada para borrar la aprobación actual de un ID de token determinado
237 * Se revierte si la dirección dada no es realmente la propietaria del token
238 */
239 function _clearApproval(address owner, uint256 _pizzaId) private {
240 require(pizzaToOwner[_pizzaId] == owner, "Debe ser el propietario de la pizza.");
241 require(_exists(_pizzaId), "La pizza no existe.");
242 if (pizzaApprovals[_pizzaId] != address(0)) {
243 pizzaApprovals[_pizzaId] = address(0);
244 }
245 }
246
247 /*
248 * Establece o anula la aprobación de un operador determinado
249 * Un operador puede transferir todos los tokens del remitente en su nombre
250 */
251 function setApprovalForAll(address to, bool approved) public {
252 require(to != msg.sender, "No se puede aprobar la propia dirección");
253 operatorApprovals[msg.sender][to] = approved;
254 emit ApprovalForAll(msg.sender, to, approved);
255 }
256
257 // Indica si un operador está aprobado por un propietario determinado
258 function isApprovedForAll(address owner, address operator)
259 public
260 view
261 returns (bool)
262 {
263 return operatorApprovals[owner][operator];
264 }
265
266 // Toma la propiedad de la pizza: solo para usuarios aprobados
267 function takeOwnership(uint256 _pizzaId) public {
268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "La dirección no está aprobada.");
269 address owner = this.ownerOf(_pizzaId);
270 this.transferFrom(owner, msg.sender, _pizzaId);
271 }
272
273 // Comprueba si la pizza existe
274 function _exists(uint256 pizzaId) internal view returns (bool) {
275 address owner = pizzaToOwner[pizzaId];
276 return owner != address(0);
277 }
278
279 // Comprueba si la dirección es la propietaria o está aprobada para transferir la pizza
280 function _isApprovedOrOwner(address spender, uint256 pizzaId)
281 internal
282 view
283 returns (bool)
284 {
285 address owner = pizzaToOwner[pizzaId];
286 // Desactivar la comprobación de solium debido a
287 // https://github.com/duaraghav8/Solium/issues/175
288 // solium-disable-next-line operator-whitespace
289 return (spender == owner ||
290 this.getApproved(pizzaId) == spender ||
291 this.isApprovedForAll(owner, spender));
292 }
293
294 // Comprueba si la pizza es única y no existe todavía
295 modifier isUnique(string memory _name, uint256 _dna) {
296 bool result = true;
297 for (uint256 i = 0; i < pizzas.length; i++) {
298 if (
299 keccak256(abi.encodePacked(pizzas[i].name)) ==
300 keccak256(abi.encodePacked(_name)) &&
301 pizzas[i].dna == _dna
302 ) {
303 result = false;
304 }
305 }
306 require(result, "Ya existe una pizza con ese nombre.");
307 _;
308 }
309
310 // Devuelve si la dirección de destino es un contrato
311 function isContract(address account) internal view returns (bool) {
312 uint256 size;
313 // Actualmente no hay una forma mejor de comprobar si hay un contrato en una dirección
314 // que comprobar el tamaño del código en esa dirección.
315 // Consulte https://ethereum.stackexchange.com/a/14016/36603
316 // para obtener más detalles sobre cómo funciona.
317 // TODO: Vuelva a comprobar esto antes del lanzamiento de Serenity, porque entonces todas las direcciones serán
318 // contratos.
319 // solium-disable-next-line security/no-inline-assembly
320 assembly {
321 size := extcodesize(account)
322 }
323 return size > 0;
324 }
325}
Mostrar todo

Lecturas adicionales

Revise la documentación de Solidity y Vyper para ver una descripción más completa de los contratos inteligentes:

¿Le ha resultado útil este artículo?