Vai al contenuto principale

Aiuta ad aggiornare questa pagina

🌏

C'è una nuova versione di questa pagina, ma al momento è solo in inglese. Aiutaci a tradurre l'ultima versione.

Traduci la pagina
Visualizza in inglese

Nessun bug qui!🐛

Questa pagina non è stata tradotta. Per il momento, è stata intenzionalmente lasciata in inglese.

Anatomia degli Smart Contract

Ultima modifica: , Invalid DateTime
Modifica la pagina

Uno Smart Contract è un programma che viene eseguito a un indirizzo di Ethereum. È composto di dati e funzioni che entrano in esecuzione appena si riceve una transazione. Ecco una panoramica di cosa costituisce uno Smart Contract.

Prerequisiti

È necessario avere famigliarità con gli Smart Contract. Questa pagina presuppone che si conoscano i linguaggi di programmazione come JavaScript o Python.

Dati

Tutti i dati del contratto devono essere assegnati a una posizione: storage oppure memory. Modificare lo storage in uno Smart Contract è dispendioso, perciò è opportuno valutare in anticipo dove devono essere posizionati i dati.

Storage

I dati persistenti sono detti storage (o spazio di archiviazione) e sono rappresentati da variabili di stato. Questi valori sono memorizzati permanentemente nella blockchain. È necessario dichiarare il tipo così che il contratto possa tenere traccia di quanto storage è necessario sulla blockchain quando viene compilato.

1// Esempio in Solidity
2contract SimpleStorage {
3 uint storedData; // Variabile di stato
4 // ...
5}
6
📋 Copia
1# Esempio in Vyper
2storedData: int128
3
📋 Copia

Se hai già programmato con linguaggi orientati agli oggetti, è probabile che tu abbia famigliarità con la maggior parte dei tipi, ma address potrebbe non essere noto se non hai mai sviluppato per Ethereum.

Un tipo address può contenere un indirizzo Ethereum che equivale a 20 byte o 160 bit. Restituisce una notazione esadecimale preceduta da 0x.

Altri tipi includono:

  • booleano
  • numero intero
  • numeri a virgola fissa
  • array di byte a dimensione fissa
  • array di byte di dimensioni dinamiche
  • letterali interi e razionali
  • stringhe
  • letterali esadecimali
  • enumerazioni

Per ulteriori spiegazioni, consulta la documentazione:

  • Vedi Vyper types
  • Vedi Solidity types

Memory

I valori che vengono memorizzati solo per la durata di esecuzione di una funzione di contratto sono detti variabili di memoria. Dal momento che non sono memorizzati in modo permanente sulla blockchain, sono molto più economici da usare.

Scopri di più su come l'EVM memorizza i dati (storage, memory e stack) in Solidity docs.

Variabili d'ambiente

Oltre alle variabili che vengono definite nel contratto, sono presenti alcune variabili globali speciali. Vengono utilizzate principalmente per fornire informazioni sulla blockchain o sulla transazione corrente.

Esempi:

ProprietàVariabile di statoDescrizione
block.timestampuint256Data/ora dell'epoca del blocco corrente
msg.senderaddressMittente del messaggio (chiamata corrente)

Funzioni

In termini estremamente semplici, le funzioni possono ottenere informazioni o impostarle in risposta alle transazioni in arrivo.

Ci sono due tipi di chiamata di funzione:

  • internal – non creano una chiamata all'EVM
    • Le funzioni interne e le variabili di stato sono accessibili solo internamente (ovvero dall'interno del contratto corrente o dei contratti derivanti da esso).
  • external – creano una chiamata all'EVM
    • Le funzioni esterne fanno parte dell'interfaccia del contratto, quindi possono essere chiamate da altri contratti e tramite transazioni. Una funzione esterna f non può essere chiamata internamente (quindi f() non funziona, ma this.f() funziona).

Possono anche essere public o private

  • Le funzioni public possono essere chiamate direttamente dall'interno del contratto o dall'esterno tramite messaggi
  • Le funzioni private sono visibili solo per il contratto in cui sono definite e non da contratti derivati

Sia le funzioni che le variabili di stato possono essere rese pubbliche o private

Questa è una funzione per aggiornare una variabile di stato su un contratto:

1// Esempio in Solidity
2function update_name(string value) public {
3 dapp_name = value;
4}
5
📋 Copia
  • Il parametro value di tipo string viene passato alla funzione: update_name
  • È dichiarato public e quindi chiunque può accedervi
  • Non è dichiarato view, quindi può modificare lo stato del contratto

Funzioni view

Queste funzioni promettono di non modificare lo stato dei dati del contratto. Tra gli esempi più comuni vi sono le funzioni "getter": puoi usarle ad esempio per ricevere un saldo dell'utente.

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

Ecco cosa è considerato modifica dello stato:

  1. Scrittura su variabili di stato.
  2. Emissione di eventi.
  3. Creazione di altri contratti.
  4. Uso di selfdestruct.
  5. Invio di ether tramite chiamate.
  6. Chiamata di qualsiasi funzione non contrassegnata con view o pure.
  7. Utilizzo di chiamate di basso livello.
  8. Utilizzo di assembly inline contenente determinati opcode.

Funzioni constructor

Quando il contratto viene distribuito per la prima volta, le funzioni constructor sono eseguite solo una volta. Come accade per constructor in molti linguaggi di programmazione basati su classi, queste funzioni spesso inizializzano le variabili di stato ai valori specificati.

1// Esempi in Solidity
2// Inizializza i dati del contratto, impostando `owner`
3// sull'indirizzo del creatore del contratto.
4constructor() public {
5 // Tutti gli Smart Contract si basano su transazioni esterne per attivare le proprie funzioni.
6 // `msg` è una variabile globale che include dati sulla transazione specificata,
7 // come indirizzo del mittente e valore degli ETH inclusi nella transazione.
8 // Per saperne di più: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
9 owner = msg.sender;
10}
11
Mostra tutto
📋 Copia
1# Esempio in 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
8
📋 Copia

Funzioni integrate

Oltre alle variabili che vengono definite nel contratto, sono presenti alcune funzioni speciali integrate. L'esempio più evidente è:

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

Queste permettono ai contratti di inviare ETH ad altri account.

Scrivere funzioni

Una funzione ha bisogno di:

  • variabile e tipo di parametro (se accetta parametri)
  • dichiarazione interna/esterna
  • dichiarazione pure/view/payable
  • tipo di valore restituito (se restituisce un valore)
1pragma solidity >=0.4.0 <=0.6.0;
2
3contract ExampleDapp {
4 string dapp_name; // state variable
5
6 // Called when the contract is deployed and initializes the value
7 constructor() public {
8 dapp_name = "My Example dapp";
9 }
10
11 // Get Function
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // Set Function
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
21
Mostra tutto
📋 Copia

Un contratto completo potrebbe avere questa forma. Qui la funzione constructor fornisce un valore iniziale per la variabile dapp_name.

Eventi e log

Gli eventi consentono di comunicare con uno Smart Contract dal frontend o da altre applicazioni che prevedono un'iscrizione. In seguito al mining di una transazione, gli Smart Contract possono emettere eventi e scrivere log sulla blockchain che il frontend può quindi elaborare.

Esempi commentati

Questi sono alcuni esempi scritti in Solidity. Se vuoi sperimentare con il codice, puoi interagire con questi esempi in Remix.

Hello world

1// Specifica la versione di Solidity, utilizzando il controllo delle versioni semantico.
2// Per saperne di più: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// Definisce un contratto chiamato `HelloWorld`.
6// Un contratto è una raccolta di funzioni e dati (il suo stato).
7// Una volta distribuito, un contratto risiede in un indirizzo specifico della blockchain Ethereum.
8// Per saperne di più: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
9contract HelloWorld {
10
11 // Dichiara una variabile di stato `message` di tipo `string`.
12 // Le variabili di stato sono variabili con valori memorizzati in modo permanente nello spazio di archiviazione (storage) del contratto.
13 // La parola chiave `public` rende le variabili accessibili dall'esterno di un contratto
14 // e crea una funzione che altri contratti o client possono chiamare per accedere al valore.
15 string public message;
16
17 // Analogamente a molti linguaggi di programmazione basati su classi, un costruttore è
18 // una funzione speciale che viene eseguita solo al momento della creazione del contratto.
19 // I costruttori sono utilizzati per inizializzare i dati del contratto.
20 // Maggiori informazioni: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
21 constructor(string memory initMessage) public {
22 // Accetta un argomento di tipo string `initMessage` e imposta il valore
23 // nella variabile di archiviazione `message` del contratto).
24 message = initMessage;
25 }
26
27 // Funzione pubblica che accetta un argomento string
28 // e aggiorna la variabile di archiviazione `message`.
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
33
Mostra tutto
📋 Copia

Token

1pragma solidity ^0.5.10;
2
3contract Token {
4 // Un 'address' è paragonabile a un indirizzo email. Viene usato per identificare un account su Ethereum.
5 // Gli indirizzi possono rappresentare uno Smart Contract o un account esterno (utente).
6 // Per saperne di più: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // Un `mapping` è essenzialmente una struttura dati di tipo tabella hash.
10 // Questo `mapping` assegna un numero intero senza segno (il saldo del token) a un indirizzo (il proprietario del token).
11 // Per saperne di più: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // Gli eventi consentono di registrare le attività sulla blockchain.
15 // I client Ethereum possono attendere gli eventi per reagire alle modifiche di stato del contratto.
16 // Ulteriori informazioni: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
17 event Transfer(address from, address to, uint amount);
18
19 // Inizializza i dati del contratto, impostando `owner`
20 // sull'indirizzo del creatore del contratto.
21 constructor() public {
22 // Tutti gli Smart Contract si basano su transazioni esterne per attivare le proprie funzioni.
23 // `msg` è una variabile globale che include dati relativi alla transazione specificata,
24 // come l'indirizzo del mittente e il valore in ETH incluso nella transazione.
25 // Per saperne di più: 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 quantità di nuovi token e li invia a un indirizzo.
30 function mint(address receiver, uint amount) public {
31 // `require` è una struttura di controllo utilizzata per implementare determinate condizioni.
32 // Se un'istruzione `require` restituisce `false`, viene attivata un'eccezione,
33 // che ripristina tutte le modifiche apportate allo stato durante la chiamata corrente.
34 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
35
36 // Only the contract owner can call this function
37 require(msg.sender == owner, "You are not the owner.");
38
39 // Enforces a maximum amount of tokens
40 require(amount < 1e60, "Maximum issuance exceeded");
41
42 // Increases the balance of `receiver` by `amount`
43 balances[receiver] += amount;
44 }
45
46 // Sends an amount of existing tokens from any caller to an address.
47 function transfer(address receiver, uint amount) public {
48 // Il mittente deve avere abbastanza token da inviare
49 require(amount <= balances[msg.sender], "Insufficient balance.");
50
51 // Modifica i saldi di token dei due indirizzi
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // Emette l'evento definito in precedenza
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
59
Mostra tutto
📋 Copia

Risorsa digitale univoca

1pragma solidity ^0.5.10;
2
3// Importa simboli da altri file nel contratto corrente.
4// In questo caso, una serie di contratti di supporto da OpenZeppelin.
5// Per saperne di più: 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 parola chiave `is` viene utilizzata per ereditare funzioni e parole chiave da contratti esterni.
13// In questo caso, `CryptoPizza` eredita dai contratti `IERC721` e `ERC165`.
14// Per saperne di più: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
15contract CryptoPizza is IERC721, ERC165 {
16 // Utilizza la libreria SafeMath di OpenZeppelin per eseguire operazioni aritmetiche in modo sicuro.
17 // Ulteriori informazioni: https://docs.openzeppelin.com/contracts/2. /api/math#SafeMath
18 using SafeMath for uint256;
19
20 // Le variabili di stato costanti in Solidity sono simili ad altri linguaggi
21 // ma devono essere assegnate da un'espressione che è costante al momento della compilazione.
22 // Learn more: 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 // Struct types let you define your own type
28 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // Creates an empty array of Pizza structs
35 Pizza[] public pizzas;
36
37 // Mapping from pizza ID to its owner's address
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // Mapping from owner's address to number of owned token
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // Mapping from token ID to approved address
44 mapping(uint256 => address) pizzaApprovals;
45
46 // You can nest mappings, this example maps owner to operator approvals
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // Internal function to create a random Pizza from string (name) and DNA
50 function _createPizza(string memory _name, uint256 _dna)
51 // The `internal` keyword means this function is only visible
52 // within this contract and contracts that derive this contract
53 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
54 internal
55 // `isUnique` is a function modifier that checks if the pizza already exists
56 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // Adds Pizza to array of Pizzas and get id
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // Checks that Pizza owner is the same as current user
63 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64 assert(pizzaToOwner[id] == address(0));
65
66 // Maps the Pizza to the owner
67 pizzaToOwner[id] = msg.sender;
68 ownerPizzaCount[msg.sender] = SafeMath.add(
69 ownerPizzaCount[msg.sender],
70 1
71 );
72 }
73
74 // Creates a random Pizza from string (name)
75 function createRandomPizza(string memory _name) public {
76 uint256 randDna = generateRandomDna(_name, msg.sender);
77 _createPizza(_name, randDna);
78 }
79
80 // Generates random DNA from string (name) and address of the owner (creator)
81 function generateRandomDna(string memory _str, address _owner)
82 public
83 // Functions marked as `pure` promise not to read from or modify the state
84 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
85 pure
86 returns (uint256)
87 {
88 // Generates random uint from string (name) + address (owner)
89 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
90 uint256(_owner);
91 rand = rand % dnaModulus;
92 return rand;
93 }
94
95 // Returns array of Pizzas found by owner
96 function getPizzasByOwner(address _owner)
97 public
98 // Functions marked as `view` promise not to modify state
99 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
100 view
101 returns (uint256[] memory)
102 {
103 // Uses the `memory` storage location to store values only for the
104 // lifecycle of this function call.
105 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
106 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
107 uint256 counter = 0;
108 for (uint256 i = 0; i < pizzas.length; i++) {
109 if (pizzaToOwner[i] == _owner) {
110 result[counter] = i;
111 counter++;
112 }
113 }
114 return result;
115 }
116
117 // Transfers Pizza and ownership to other address
118 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
119 require(_from != address(0) && _to != address(0), "Invalid address.");
120 require(_exists(_pizzaId), "Pizza does not exist.");
121 require(_from != _to, "Cannot transfer to the same address.");
122 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
123
124 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
125 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
126 pizzaToOwner[_pizzaId] = _to;
127
128 // Emits event defined in the imported IERC721 contract
129 emit Transfer(_from, _to, _pizzaId);
130 _clearApproval(_to, _pizzaId);
131 }
132
133 /**
134 * Safely transfers the ownership of a given token ID to another address
135 * If the target address is a contract, it must implement `onERC721Received`,
136 * which is called upon a safe transfer, and return the magic value
137 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
138 * otherwise, the transfer is reverted.
139 */
140 function safeTransferFrom(address from, address to, uint256 pizzaId)
141 public
142 {
143 // solium-disable-next-line arg-overflow
144 this.safeTransferFrom(from, to, pizzaId, "");
145 }
146
147 /**
148 * Safely transfers the ownership of a given token ID to another address
149 * If the target address is a contract, it must implement `onERC721Received`,
150 * which is called upon a safe transfer, and return the magic value
151 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
152 * otherwise, the transfer is reverted.
153 */
154 function safeTransferFrom(
155 address from,
156 address to,
157 uint256 pizzaId,
158 bytes memory _data
159 ) public {
160 this.transferFrom(from, to, pizzaId);
161 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implmement onERC721Received.");
162 }
163
164 /**
165 * Internal function to invoke `onERC721Received` on a target address
166 * The call is not executed if the target address is not a contract
167 */
168 function _checkOnERC721Received(
169 address from,
170 address to,
171 uint256 pizzaId,
172 bytes memory _data
173 ) internal returns (bool) {
174 if (!isContract(to)) {
175 return true;
176 }
177
178 bytes4 retval = IERC721Receiver(to).onERC721Received(
179 msg.sender,
180 from,
181 pizzaId,
182 _data
183 );
184 return (retval == _ERC721_RECEIVED);
185 }
186
187 // Burns a Pizza - destroys Token completely
188 // The `external` function modifier means this function is
189 // part of the contract interface and other contracts can call it
190 function burn(uint256 _pizzaId) external {
191 require(msg.sender != address(0), "Invalid address.");
192 require(_exists(_pizzaId), "Pizza does not exist.");
193 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
194
195 ownerPizzaCount[msg.sender] = SafeMath.sub(
196 ownerPizzaCount[msg.sender],
197 1
198 );
199 pizzaToOwner[_pizzaId] = address(0);
200 }
201
202 // Returns count of Pizzas by address
203 function balanceOf(address _owner) public view returns (uint256 _balance) {
204 return ownerPizzaCount[_owner];
205 }
206
207 // Returns owner of the Pizza found by id
208 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
209 address owner = pizzaToOwner[_pizzaId];
210 require(owner != address(0), "Invalid Pizza ID.");
211 return owner;
212 }
213
214 // Approves other address to transfer ownership of Pizza
215 function approve(address _to, uint256 _pizzaId) public {
216 require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner.");
217 pizzaApprovals[_pizzaId] = _to;
218 emit Approval(msg.sender, _to, _pizzaId);
219 }
220
221 // Returns approved address for specific Pizza
222 function getApproved(uint256 _pizzaId)
223 public
224 view
225 returns (address operator)
226 {
227 require(_exists(_pizzaId), "Pizza does not exist.");
228 return pizzaApprovals[_pizzaId];
229 }
230
231 /**
232 * Private function to clear current approval of a given token ID
233 * Reverts if the given address is not indeed the owner of the token
234 */
235 function _clearApproval(address owner, uint256 _pizzaId) private {
236 require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner.");
237 require(_exists(_pizzaId), "Pizza does not exist.");
238 if (pizzaApprovals[_pizzaId] != address(0)) {
239 pizzaApprovals[_pizzaId] = address(0);
240 }
241 }
242
243 /*
244 * Sets or unsets the approval of a given operator
245 * An operator is allowed to transfer all tokens of the sender on their behalf
246 */
247 function setApprovalForAll(address to, bool approved) public {
248 require(to != msg.sender, "Cannot approve own address");
249 operatorApprovals[msg.sender][to] = approved;
250 emit ApprovalForAll(msg.sender, to, approved);
251 }
252
253 // Tells whether an operator is approved by a given owner
254 function isApprovedForAll(address owner, address operator)
255 public
256 view
257 returns (bool)
258 {
259 return operatorApprovals[owner][operator];
260 }
261
262 // Takes ownership of Pizza - only for approved users
263 function takeOwnership(uint256 _pizzaId) public {
264 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
265 address owner = this.ownerOf(_pizzaId);
266 this.transferFrom(owner, msg.sender, _pizzaId);
267 }
268
269 // Checks if Pizza exists
270 function _exists(uint256 pizzaId) internal view returns (bool) {
271 address owner = pizzaToOwner[pizzaId];
272 return owner != address(0);
273 }
274
275 // Checks if address is owner or is approved to transfer Pizza
276 function _isApprovedOrOwner(address spender, uint256 pizzaId)
277 internal
278 view
279 returns (bool)
280 {
281 address owner = pizzaToOwner[pizzaId];
282 // Disable solium check because of
283 // https://github.com/duaraghav8/Solium/issues/175
284 // solium-disable-next-line operator-whitespace
285 return (spender == owner ||
286 this.getApproved(pizzaId) == spender ||
287 this.isApprovedForAll(owner, spender));
288 }
289
290 // Check if Pizza is unique and doesn't exist yet
291 modifier isUnique(string memory _name, uint256 _dna) {
292 bool result = true;
293 for (uint256 i = 0; i < pizzas.length; i++) {
294 if (
295 keccak256(abi.encodePacked(pizzas[i].name)) ==
296 keccak256(abi.encodePacked(_name)) &&
297 pizzas[i].dna == _dna
298 ) {
299 result = false;
300 }
301 }
302 require(result, "Pizza with such name already exists.");
303 _;
304 }
305
306 // Returns whether the target address is a contract
307 function isContract(address account) internal view returns (bool) {
308 uint256 size;
309 // Currently there is no better way to check if there is a contract in an address
310 // than to check the size of the code at that address.
311 // Visita https://ethereum.stackexchange.com/a/14016/36603
312 // per maggiori dettagli sul funzionamento.
313 // TODO Controllare questo codice nuovamente prima del rilascio di Serenity, perché a quel punto
314 // tutti gli indirizzi saranno contratti.
315 // solium-disable-next-line security/no-inline-assembly
316 assembly {
317 size := extcodesize(account)
318 }
319 return size > 0;
320 }
321}
322
Mostra tutto
📋 Copia

Letture consigliate

Consulta la documentazione di Solidity e Vyper per una panoramica più completa degli Smart Contract:

Questo articolo è stato utile?

👈

Indietro

Linguaggi dello Smart Contract

Avanti

Librerie degli Smart Contract
👉