Anatomia dei contratti intelligenti
Ultima modifica: @Herbie_23(opens in a new tab), 14 giugno 2024
Un contratto intelligente è un programma eseguito a un indirizzo su Ethereum. È composto di dati e funzioni che entrano in esecuzione appena si riceve una transazione. Ecco una panoramica di cosa compone un contratto intelligente.
Prerequisiti
Prima, assicurati di aver letto a riguardo dei contratti intelligenti. 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 l'archiviazione in un contratto intelligente è dispendioso, devi quindi considerare dove dovrebbero risiedere i tuoi 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 Solidity2contract SimpleStorage {3 uint storedData; // Variabile di stato4 // ...5}Copia
1# Esempio in Vyper2storedData: int128Copia
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:
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 (Archiviazione, Memoria e lo Stack), nella documentazione di Solidity(opens in a new tab).
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 stato | Descrizione |
---|---|---|
block.timestamp | uint256 | Data/ora dell'epoca del blocco corrente |
msg.sender | address | Mittente 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 (quindif()
non funziona, mathis.f()
funziona).
- Le funzioni esterne fanno parte dell'interfaccia del contratto, quindi possono essere chiamate da altri contratti e tramite transazioni. Una funzione esterna
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 Solidity2function update_name(string value) public {3 dapp_name = value;4}Copia
- Il parametro
value
di tipostring
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 Solidity2function balanceOf(address _owner) public view returns (uint256 _balance) {3 return ownerPizzaCount[_owner];4}Copia
1dappName: public(string)23@view4@public5def readName() -> string:6 return dappNameCopia
Ecco cosa è considerato modifica dello stato:
- Scrittura su variabili di stato.
- Emissione di eventi(opens in a new tab).
- Creazione di altri contratti(opens in a new tab).
- Uso di
selfdestruct
. - Invio di ether tramite chiamate.
- Chiamata di qualsiasi funzione non contrassegnata con
view
opure
. - Utilizzo di chiamate di basso livello.
- 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 Solidity2// 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-properties9 owner = msg.sender;10}Mostra tuttoCopia
1# Esempio in Vyper23@external4def __init__(_beneficiary: address, _bidding_time: uint256):5 self.beneficiary = _beneficiary6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_timeCopia
Funzioni integrate
Oltre alle variabili che vengono definite nel contratto, sono presenti alcune funzioni speciali integrate. L'esempio più evidente è:
address.send()
– Soliditysend(address)
– Vyper
Queste, consentono ai contratti di inviare ETH agli altri conti.
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;23contract ExampleDapp {4 string dapp_name; // state variable56 // Called when the contract is deployed and initializes the value7 constructor() public {8 dapp_name = "My Example dapp";9 }1011 // Get Function12 function read_name() public view returns(string) {13 return dapp_name;14 }1516 // Set Function17 function update_name(string value) public {18 dapp_name = value;19 }20}Mostra tuttoCopia
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 ti consentono di comunicare con il tuo contratto intelligente dal tuo frontend o da altre applicazioni che prevedono un'iscrizione. Quando una transazione è minata, i contratti intelligenti possono emettere eventi e scrivere registri alla blockchain, che il frontend può poi elaborare.
Esempi commentati
Questi sono alcuni esempi scritti in Solidity. Se vuoi sperimentare con il codice, puoi interagire con questi esempi in Remix(opens in a new tab).
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#pragma3pragma solidity ^0.5.10;45// 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.html9contract HelloWorld {1011 // 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 contratto14 // e crea una funzione che altri contratti o client possono chiamare per accedere al valore.15 string public message;1617 // 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#constructors21 constructor(string memory initMessage) public {22 // Accetta un argomento di tipo string `initMessage` e imposta il valore23 // nella variabile di archiviazione `message` del contratto).24 message = initMessage;25 }2627 // Funzione pubblica che accetta un argomento string28 // e aggiorna la variabile di archiviazione `message`.29 function update(string memory newMessage) public {30 message = newMessage;31 }32}Mostra tuttoCopia
Token
1pragma solidity ^0.5.10;23contract 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#address7 address public owner;89 // 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-types12 mapping (address => uint) public balances;1314 // 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#events17 event Transfer(address from, address to, uint amount);1819 // 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-properties26 owner = msg.sender;27 }2829 // 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-exceptions3536 // Only the contract owner can call this function37 require(msg.sender == owner, "You are not the owner.");3839 // Enforces a maximum amount of tokens40 require(amount < 1e60, "Maximum issuance exceeded");4142 // Increases the balance of `receiver` by `amount`43 balances[receiver] += amount;44 }4546 // 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 inviare49 require(amount <= balances[msg.sender], "Insufficient balance.");5051 // Modifica i saldi di token dei due indirizzi52 balances[msg.sender] -= amount;53 balances[receiver] += amount;5455 // Emette l'evento definito in precedenza56 emit Transfer(msg.sender, receiver, amount);57 }58}Mostra tuttoCopia
Risorsa digitale univoca
1pragma solidity ^0.5.10;23// 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-files67import "../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";1112// 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#inheritance15contract 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#SafeMath18 using SafeMath for uint256;1920 // Le variabili di stato costanti in Solidity sono simili ad altri linguaggi21 // ma devono essere assegnate da un'espressione che è costante al momento della compilazione.22 // Scopri di più: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables23 uint256 constant dnaDigits = 10;24 uint256 constant dnaModulus = 10 ** dnaDigits;25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;2627 // I tipi di struttura ti fanno definire il tuo tipo28 // Scopri di più: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs29 struct Pizza {30 string name;31 uint256 dna;32 }3334 // Crea un insieme vuoto di strutture di Pizza35 Pizza[] public pizzas;3637 // Mappatura dall'ID della pizza all'indirizzo del suo proprietario38 mapping(uint256 => address) public pizzaToOwner;3940 // Mappatura dall'indirizzo del proprietario al numero di token posseduti41 mapping(address => uint256) public ownerPizzaCount;4243 // Mappatura dall'ID del token all'indirizzo approvato44 mapping(uint256 => address) pizzaApprovals;4546 // Puoi nidificare le mappature, questo esempio mappa le approvazioni da proprietario a operatore47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // Funzione interna per creare una Pizza casuale dalla stringa (nome) e dal DNA50 function _createPizza(string memory _name, uint256 _dna)51 // La parola chiave `internal` significa che questa funzione è visibile solo52 // tra questo contratto e i contratti derivati da esso53 // Scopri di più: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters54 internal55 // `isUnique` è un modificatore della funzione che verifica se la pizza esiste già56 // Scopri di più: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers57 isUnique(_name, _dna)58 {59 // Aggiunge la Pizza all'insieme di Pizze e ottiene l'id60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // Verifica che il proprietario della Pizza sia l'utente corrente63 // Scopri di più: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions6465 // nota che address(0) è l'indirizzo zero,66 // indicando che pizza[id] non è ancora allocato a un utente in particolare.6768 assert(pizzaToOwner[id] == address(0));6970 // Mappa la Pizza al proprietario71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // Crea una Pizza casuale dalla stringa (nome)79 function createRandomPizza(string memory _name) public {80 uint256 randDna = generateRandomDna(_name, msg.sender);81 _createPizza(_name, randDna);82 }8384 // Genera DNA casuale dalla stringa (nome) e dall'indirizzo del proprietario (creatore)85 function generateRandomDna(string memory _str, address _owner)86 public87 // Le funzioni contrassegnate come `pure` promettono di non modificare lo stato o non leggere da esso88 // Scopri di più: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 returns (uint256)91 {92 // Genera uint casuale dalla stringa (nome) + indirizzo (proprietario)93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +94 uint256(_owner);95 rand = rand % dnaModulus;96 return rand;97 }9899 // Restituisce l'insieme di Pizze trovate dal proprietario100 function getPizzasByOwner(address _owner)101 public102 // Le funzioni contrassegnate come `view` promettono di non modificare lo stato103 // Scopri di più: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions104 view105 returns (uint256[] memory)106 {107 // Usa la posizione d'archiviazione `memory` per memorizzare i valori solo per la durata108 // di questa chiamata alla funzione.109 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack110 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 }120121 // Transfers Pizza and ownership to other address122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {123 require(_from != address(0) && _to != address(0), "Invalid address.");124 require(_exists(_pizzaId), "Pizza does not exist.");125 require(_from != _to, "Cannot transfer to the same address.");126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");127128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);130 pizzaToOwner[_pizzaId] = _to;131132 // Emits event defined in the imported IERC721 contract133 emit Transfer(_from, _to, _pizzaId);134 _clearApproval(_to, _pizzaId);135 }136137 /**138 * Safely transfers the ownership of a given token ID to another address139 * If the target address is a contract, it must implement `onERC721Received`,140 * which is called upon a safe transfer, and return the magic value141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;142 * otherwise, the transfer is reverted.143 */144 function safeTransferFrom(address from, address to, uint256 pizzaId)145 public146 {147 // solium-disable-next-line arg-overflow148 this.safeTransferFrom(from, to, pizzaId, "");149 }150151 /**152 * Safely transfers the ownership of a given token ID to another address153 * If the target address is a contract, it must implement `onERC721Received`,154 * which is called upon a safe transfer, and return the magic value155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;156 * otherwise, the transfer is reverted.157 */158 function safeTransferFrom(159 address from,160 address to,161 uint256 pizzaId,162 bytes memory _data163 ) public {164 this.transferFrom(from, to, pizzaId);165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");166 }167168 /**169 * Funzione interna per invocare `onERC721Received` su un dato indirizzo170 * La chiamata non è eseguita se l'indirizzo di destinazione non è un contratto171 */172 function _checkOnERC721Received(173 address from,174 address to,175 uint256 pizzaId,176 bytes memory _data177 ) internal returns (bool) {178 if (!isContract(to)) {179 return true;180 }181182 bytes4 retval = IERC721Receiver(to).onERC721Received(183 msg.sender,184 from,185 pizzaId,186 _data187 );188 return (retval == _ERC721_RECEIVED);189 }190191 // Brucia una Pizza - distrugge completamente il Token192 // Il modificatore della funzione `external` significa che questa funzione fa193 // parte dell'interfaccia del contratto e che gli altri contratti possono chiamarla194 function burn(uint256 _pizzaId) external {195 require(msg.sender != address(0), "Indirizzo non valido.");196 require(_exists(_pizzaId), "La Pizza non esiste.");197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Indirizzo non approvato.");198199 ownerPizzaCount[msg.sender] = SafeMath.sub(200 ownerPizzaCount[msg.sender],201 1202 );203 pizzaToOwner[_pizzaId] = address(0);204 }205206 // Restituisce il numero di Pizze per indirizzo207 function balanceOf(address _owner) public view returns (uint256 _balance) {208 return ownerPizzaCount[_owner];209 }210211 // Restituisce il proprietario della Pizza trovato per id212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {213 address owner = pizzaToOwner[_pizzaId];214 require(owner != address(0), "ID della Pizza non valido.");215 return owner;216 }217218 // Approva altri indirizzi per trasferire la proprietà della Pizza219 function approve(address _to, uint256 _pizzaId) public {220 require(msg.sender == pizzaToOwner[_pizzaId], "Dev'essere il proprietario della Pizza.");221 pizzaApprovals[_pizzaId] = _to;222 emit Approval(msg.sender, _to, _pizzaId);223 }224225 // Restituisce l'indirizzo approvato per la Pizza specifica226 function getApproved(uint256 _pizzaId)227 public228 view229 returns (address operator)230 {231 require(_exists(_pizzaId), "La Pizza non esiste.");232 return pizzaApprovals[_pizzaId];233 }234235 /**236 * La funzione privata per cancellare l'approvazione corrente dell'ID di un dato token237 * Si ripristina se l'indirizzo dato non è il proprietario del token238 */239 function _clearApproval(address owner, uint256 _pizzaId) private {240 require(pizzaToOwner[_pizzaId] == owner, "Dev'essere il proprietario della pizza.");241 require(_exists(_pizzaId), "La Pizza non esiste.");242 if (pizzaApprovals[_pizzaId] != address(0)) {243 pizzaApprovals[_pizzaId] = address(0);244 }245 }246247 /*248 * Imposta o rimuove l'approvazione di un dato operatore249 * Un operatore può trasferire tutti i token del mittente per conto suo250 */251 function setApprovalForAll(address to, bool approved) public {252 require(to != msg.sender, "Impossibile approvare il proprio indirizzo");253 operatorApprovals[msg.sender][to] = approved;254 emit ApprovalForAll(msg.sender, to, approved);255 }256257 // Dice se un operatore è approvato da un dato proprietario258 function isApprovedForAll(address owner, address operator)259 public260 view261 returns (bool)262 {263 return operatorApprovals[owner][operator];264 }265266 // Prende proprietà della Pizza - solo per gli utenti approvati267 function takeOwnership(uint256 _pizzaId) public {268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "L'indirizzo non è approvato.");269 address owner = this.ownerOf(_pizzaId);270 this.transferFrom(owner, msg.sender, _pizzaId);271 }272273 // Verifica se la Pizza esiste274 function _exists(uint256 pizzaId) internal view returns (bool) {275 address owner = pizzaToOwner[pizzaId];276 return owner != address(0);277 }278279 // Verifica se l'indirizzo è il proprietario o è approvato per trasferire la Pizza280 function _isApprovedOrOwner(address spender, uint256 pizzaId)281 internal282 view283 returns (bool)284 {285 address owner = pizzaToOwner[pizzaId];286 // Disabilita il controllo di solium a causa di287 // https://github.com/duaraghav8/Solium/issues/175288 // solium-disable-next-line operator-whitespace289 return (spender == owner ||290 this.getApproved(pizzaId) == spender ||291 this.isApprovedForAll(owner, spender));292 }293294 // Verifica se la Pizza è univoca e non esiste ancora295 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 == _dna302 ) {303 result = false;304 }305 }306 require(result, "Una Pizza con quel nome esiste già.");307 _;308 }309310 // Restituisce se l'indirizzo di destinazione è un contratto311 function isContract(address account) internal view returns (bool) {312 uint256 size;313 // Correntemente non c'è modo migliore di verificare se esiste un contratto in un indirizzo314 // se non controllare la dimensione del codice a quell'indirizzo.315 // Visita https://ethereum.stackexchange.com/a/14016/36603316 // per maggiori dettagli sul funzionamento.317 // TODO Controllare questo codice nuovamente prima del rilascio di Serenity, perché a quel punto318 // tutti gli indirizzi saranno contratti.319 // solium-disable-next-line security/no-inline-assembly320 assembly {321 size := extcodesize(account)322 }323 return size > 0;324 }325}Mostra tuttoCopia
Letture consigliate
Dai un'occhiata alla documentazione di Solidity e Vyper per una panoramica più complessa dei contratti intelligenti:
Argomenti correlati
Tutorial correlati
- Ridimensionare i contratti per contrastare il limite di dimensioni del contratto: Alcuni consigli pratici per ridurre le dimensioni del tuo contratto intelligente.
- Registrare dati dai contratti intelligenti con gli eventi: Un'introduzione agli eventi dei contratti intelligenti e a come puoi usarli per registrare i dati.
- Interagire con gli altri contratti da Solidity: Come distribuire un contratto intelligente da un contratto esistente e interagirvi.