Passer au contenu principal
Change page

Anatomie des contrats intelligents

Dernière mise à jour de la page : 23 février 2026

Les contrats intelligents sont des programmes qui s'exécutent à une adresse sur Ethereum. Ils sont constitués de données et de fonctions qui peuvent s'exécuter lors de la réception d'une transaction. Cette page explique la composition d'un contrat intelligent.

Prérequis

Assurez-vous d'avoir d'abord lu la page sur les contrats intelligents. Ce document part du principe que vous êtes déjà familiarisé avec des langages de programmation comme JavaScript ou Python.

Données

Toute donnée de contrat doit être affectée à un emplacement : soit storage, soit memory. Il est coûteux de modifier le stockage dans un contrat intelligent. Vous devez donc décider de l'endroit où vous souhaitez conserver vos données.

Stockage

Les données persistantes sont appelées stockage et sont représentées par des variables d'état. Ces valeurs sont stockées en permanence sur la blockchain. Vous devez déclarer le type afin que le contrat puisse garder une trace de la quantité de stockage nécessaire sur la blockchain quand il compile.

1// Exemple Solidity
2contract SimpleStorage {
3 uint storedData; // Variable d'état
4 // ...
5}
1# Vyper example
2storedData: int128

Si vous avez déjà programmé des langages orientés objet, vous serez probablement familiarisé avec la plupart des types. Cependant, address devrait être nouveau pour vous si vous débutez dans le développement Ethereum.

Un type address peut contenir une adresse Ethereum qui équivaut à 20 octets ou 160 bits. ce qui donne une adresse en notation hexadécimale commençant par 0x.

Les autres types incluent les :

  • booléens ;
  • nombres entiers ;
  • numéros de points fixes ;
  • tableaux d'octets de taille fixe ;
  • tableaux d'octets de taille dynamique
  • littéraux rationnels et entiers
  • littéraux de chaîne
  • littéraux hexadécimaux
  • énumérations

Pour plus d'explications, consultez les pages ci-dessous :

Mémoire

Les valeurs qui ne sont stockées que pendant la durée de l'exécution d'une fonction de contrat sont appelées variables de mémoire. Celles-ci n'étant pas stockées de façon permanente sur la blockchain, elles sont donc moins chères à utiliser.

Apprenez-en davantage sur la façon dont l'EVM stocke les données (le stockage, la mémoire et la pile) dans la documentation de Solidityopens in a new tab.

Variables d'environnement

En plus des variables que vous définissez sur votre contrat, il existent quelques variables globales spéciales. Elles sont principalement utilisées pour fournir des informations sur la blockchain ou la transaction en cours.

Exemples :

PropriétéVariable d'étatDescription
block.timestampuint256Horodatage de la période du bloc actuel
msg.senderAdresseExpéditeur du message (appel en cours)

Fonctions

En termes simples, les fonctions peuvent obtenir ou définir des informations en réponse à des transactions entrantes.

Il existe deux types d'appels de fonctions :

  • internal – celles-ci ne créent pas d'appel EVM
    • Les fonctions internes et les variables d'état ne sont accessibles qu'en interne (c'est-à-dire depuis le contrat actuel ou les contrats qui en dérivent)
  • external – celles-ci créent un appel EVM
    • Les fonctions externes font partie de l'interface du contrat, ce qui signifie qu'elles peuvent être appelées à partir d'autres contrats et via des transactions. Une fonction externe f ne peut pas être appelée en interne (c.-à-d. que f() ne fonctionne pas, mais this.f() fonctionne).

Elles peuvent également être public ou private

  • Les fonctions public peuvent être appelées en interne depuis le contrat ou en externe via des messages
  • Les fonctions private ne sont visibles que pour le contrat dans lequel elles sont définies et non dans les contrats dérivés

Les fonctions et les variables d'état peuvent être rendues publiques ou privées

Voici une fonction pour mettre à jour une variable d'état sur un contrat :

1// Solidity example
2function update_name(string value) public {
3 dapp_name = value;
4}
  • Le paramètre value de type string est passé dans la fonction : update_name
  • Elle est déclarée public, ce qui signifie que n'importe qui peut y accéder
  • Elle n'est pas déclarée view, elle peut donc modifier l'état du contrat

Fonctions View

Ces fonctions promettent de ne pas modifier l’état des données du contrat. Les exemples courants sont les fonctions « getter » - vous pouvez utiliser ceci pour obtenir le solde d'un utilisateur par exemple.

1// Solidity example
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

Voici ce qui est considéré comme une modification d'état :

  1. Écriture dans les variables d'état
  2. Émettre des événementsopens in a new tab.
  3. Créer d'autres contratsopens in a new tab.
  4. Utiliser selfdestruct.
  5. Envoi d'ether via des appels
  6. Appeler toute fonction non marquée view ou pure.
  7. Utilisation d'appels de bas niveau
  8. Utilisation d'un assemblage en ligne conteant certains opcodes

Fonctions constructeur

Les fonctions constructor ne sont exécutées qu'une seule fois lors du premier déploiement du contrat. Comme le constructor dans de nombreux langages de programmation orientés objet, ces fonctions initialisent souvent les variables d'état à leurs valeurs spécifiées.

1// Exemple Solidity
2// Initialise les données du contrat, en définissant l'`owner`
3// sur l'adresse du créateur du contrat.
4constructor() public {
5 // Tous les contrats intelligents s'appuient sur des transactions externes pour déclencher leurs fonctions.
6 // `msg` est une variable globale qui inclut des données pertinentes sur la transaction donnée,
7 // comme l'adresse de l'expéditeur et la valeur en ETH incluse dans la transaction.
8 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
9 owner = msg.sender;
10}
Afficher tout
1# Vyper example
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

Fonctions intégrées

En plus des variables et des fonctions que vous définissez pour votre contrat, il existe des fonctions spéciales intégrées. Exemple le plus évident :

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

Celles-ci permettent aux contrats d’envoyer des ETH à d’autres comptes.

Écrire des fonctions

Votre fonction a besoin des éléments suivants :

  • Paramètre variable et type (si elle accepte des paramètres)
  • Déclaration de fonction internal/external
  • Déclaration de fonction pure/view/payable
  • Type de renvoi (si elle renvoie une valeur)
1pragma solidity >=0.4.0 <=0.6.0;
2
3contract ExampleDapp {
4 string dapp_name; // variable d'état
5
6 // Appelé lorsque le contrat est déployé et initialise la valeur
7 constructor() public {
8 dapp_name = "Ma dapp d'exemple";
9 }
10
11 // Fonction Get
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // Fonction Set
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
Afficher tout

Un contrat complet pourrait ressembler à cela. Ici, la fonction constructor fournit une valeur initiale pour la variable dapp_name.

Événements et journaux

Les événements permettent à votre contrat intelligent de communiquer avec votre frontend ou d'autres applications abonnées. Une fois qu'une transaction est validée et ajoutée à un bloc, les contrats intelligents peuvent émettre des événements et enregistrer des informations, que le frontend peut ensuite traiter et utiliser.

Exemples annotés

Voici quelques exemples rédigés en Solidity. Si vous souhaitez vous amuser avec le code, vous pouvez interagir avec celui-ci dans Remixopens in a new tab.

Hello world

1// Spécifie la version de Solidity, en utilisant le versionnage sémantique.
2// En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// Définit un contrat nommé `HelloWorld`.
6// Un contrat est une collection de fonctions et de données (son état).
7// Une fois déployé, un contrat réside à une adresse spécifique sur la blockchain Ethereum.
8// En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
9contract HelloWorld {
10
11 // Déclare une variable d'état `message` de type `string`.
12 // Les variables d'état sont des variables dont les valeurs sont stockées en permanence dans le stockage du contrat.
13 // Le mot-clé `public` rend les variables accessibles depuis l'extérieur d'un contrat
14 // et crée une fonction que d'autres contrats ou clients peuvent appeler pour accéder à la valeur.
15 string public message;
16
17 // Similaire à de nombreux langages orientés objet basés sur des classes, un constructeur est
18 // une fonction spéciale qui n'est exécutée que lors de la création du contrat.
19 // Les constructeurs sont utilisés pour initialiser les données du contrat.
20 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
21 constructor(string memory initMessage) public {
22 // Accepte un argument de chaîne `initMessage` et définit la valeur
23 // dans la variable de stockage `message` du contrat.
24 message = initMessage;
25 }
26
27 // Une fonction publique qui accepte un argument de chaîne
28 // et met à jour la variable de stockage `message`.
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
Afficher tout

Jeton

1pragma solidity ^0.5.10;
2
3contract Token {
4 // Un `address` est comparable à une adresse e-mail - il est utilisé pour identifier un compte sur Ethereum.
5 // Les adresses peuvent représenter un contrat intelligent ou des comptes externes (utilisateur).
6 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // Un `mapping` est essentiellement une structure de données de table de hachage.
10 // Ce `mapping` attribue un entier non signé (le solde de jetons) à une adresse (le détenteur de jetons).
11 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // Les événements permettent de journaliser l'activité sur la blockchain.
15 // Les clients Ethereum peuvent écouter les événements afin de réagir aux changements d'état du contrat.
16 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
17 event Transfer(address from, address to, uint amount);
18
19 // Initialise les données du contrat, en définissant l'`owner`
20 // sur l'adresse du créateur du contrat.
21 constructor() public {
22 // Tous les contrats intelligents s'appuient sur des transactions externes pour déclencher leurs fonctions.
23 // `msg` est une variable globale qui inclut des données pertinentes sur la transaction donnée,
24 // comme l'adresse de l'expéditeur et la valeur en ETH incluse dans la transaction.
25 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
26 owner = msg.sender;
27 }
28
29 // Crée un montant de nouveaux jetons et les envoie à une adresse.
30 function mint(address receiver, uint amount) public {
31 // `require` est une structure de contrôle utilisée pour appliquer certaines conditions.
32 // Si une déclaration `require` est évaluée à `false`, une exception est déclenchée,
33 // qui annule toutes les modifications apportées à l'état au cours de l'appel actuel.
34 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
35
36 // Seul le propriétaire du contrat peut appeler cette fonction
37 require(msg.sender == owner, "Vous n'êtes pas le propriétaire.");
38
39 // Applique un montant maximum de jetons
40 require(amount < 1e60, "Émission maximale dépassée");
41
42 // Augmente le solde de `receiver` de `amount`
43 balances[receiver] += amount;
44 }
45
46 // Envoie un montant de jetons existants de n'importe quel appelant à une adresse.
47 function transfer(address receiver, uint amount) public {
48 // L'expéditeur doit avoir suffisamment de jetons à envoyer
49 require(amount <= balances[msg.sender], "Solde insuffisant.");
50
51 // Ajuste les soldes de jetons des deux adresses
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // Émet l'événement défini plus tôt
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
Afficher tout

Actif numérique unique

1pragma solidity ^0.5.10;
2
3// Importe des symboles d'autres fichiers dans le contrat actuel.
4// Dans ce cas, une série de contrats d'aide d'OpenZeppelin.
5// En savoir plus : 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// Le mot-clé `is` est utilisé pour hériter des fonctions et des mots-clés de contrats externes.
13// Dans ce cas, `CryptoPizza` hérite des contrats `IERC721` et `ERC165`.
14// En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
15contract CryptoPizza is IERC721, ERC165 {
16 // Utilise la bibliothèque SafeMath d'OpenZeppelin pour effectuer des opérations arithmétiques en toute sécurité.
17 // En savoir plus : https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath
18 using SafeMath for uint256;
19
20 // Les variables d'état constantes dans Solidity sont similaires à d'autres langages
21 // mais vous devez les affecter à partir d'une expression qui est constante au moment de la compilation.
22 // En savoir plus : 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 // Les types struct vous permettent de définir votre propre type
28 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // Crée un tableau vide de structs Pizza
35 Pizza[] public pizzas;
36
37 // Mappage de l'ID de la pizza à l'adresse de son propriétaire
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // Mappage de l'adresse du propriétaire au nombre de jetons possédés
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // Mappage de l'ID du jeton à l'adresse approuvée
44 mapping(uint256 => address) pizzaApprovals;
45
46 // Vous pouvez imbriquer des mappages, cet exemple mappe le propriétaire aux approbations de l'opérateur
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // Fonction interne pour créer une Pizza aléatoire à partir d'une chaîne (nom) et d'un ADN
50 function _createPizza(string memory _name, uint256 _dna)
51 // Le mot-clé `internal` signifie que cette fonction n'est visible
52 // qu'à l'intérieur de ce contrat et des contrats qui dérivent de ce contrat
53 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
54 internal
55 // `isUnique` est un modificateur de fonction qui vérifie si la pizza existe déjà
56 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // Ajoute une Pizza au tableau de Pizzas et obtient l'ID
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // Vérifie que le propriétaire de la Pizza est le même que l'utilisateur actuel
63 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64
65 // notez que address(0) est l'adresse zéro,
66 // indiquant que pizza[id] n'est pas encore alloué à un utilisateur particulier.
67
68 assert(pizzaToOwner[id] == address(0));
69
70 // Mappe la Pizza au propriétaire
71 pizzaToOwner[id] = msg.sender;
72 ownerPizzaCount[msg.sender] = SafeMath.add(
73 ownerPizzaCount[msg.sender],
74 1
75 );
76 }
77
78 // Crée une Pizza aléatoire à partir d'une chaîne (nom)
79 function createRandomPizza(string memory _name) public {
80 uint256 randDna = generateRandomDna(_name, msg.sender);
81 _createPizza(_name, randDna);
82 }
83
84 // Génère un ADN aléatoire à partir d'une chaîne (nom) et de l'adresse du propriétaire (créateur)
85 function generateRandomDna(string memory _str, address _owner)
86 public
87 // Les fonctions marquées comme `pure` promettent de ne pas lire ou modifier l'état
88 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
89 pure
90 returns (uint256)
91 {
92 // Génère un uint aléatoire à partir d'une chaîne (nom) + adresse (propriétaire)
93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
94 uint256(_owner);
95 rand = rand % dnaModulus;
96 return rand;
97 }
98
99 // Renvoie un tableau des Pizzas trouvées par propriétaire
100 function getPizzasByOwner(address _owner)
101 public
102 // Les fonctions marquées comme `view` promettent de ne pas modifier l'état
103 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
104 view
105 returns (uint256[] memory)
106 {
107 // Utilise l'emplacement de stockage `memory` pour stocker des valeurs uniquement pour le cycle de vie de cet appel de fonction.
108 // En savoir plus : https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
109 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
110 uint256 counter = 0;
111 for (uint256 i = 0; i < pizzas.length; i++) {
112 if (pizzaToOwner[i] == _owner) {
113 result[counter] = i;
114 counter++;
115 }
116 }
117 return result;
118 }
119
120 // Transfère la Pizza et la propriété à une autre adresse
121 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
122 require(_from != address(0) && _to != address(0), "Adresse non valide.");
123 require(_exists(_pizzaId), "La pizza n'existe pas.");
124 require(_from != _to, "Impossible de transférer à la même adresse.");
125 require(_isApprovedOrOwner(msg.sender, _pizzaId), "L'adresse n'est pas approuvée.");
126
127 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
128 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
129 pizzaToOwner[_pizzaId] = _to;
130
131 // Émet un événement défini dans le contrat IERC721 importé
132 emit Transfer(_from, _to, _pizzaId);
133 _clearApproval(_to, _pizzaId);
134 }
135
136 /**
137 * Transfère en toute sécurité la propriété d'un ID de jeton donné à une autre adresse
138 * Si l'adresse cible est un contrat, elle doit implémenter `onERC721Received`,
139 * qui est appelée lors d'un transfert sécurisé, et renvoyer la valeur magique
140 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
141 * sinon, le transfert est annulé.
142 */
143 function safeTransferFrom(address from, address to, uint256 pizzaId)
144 public
145 {
146 // solium-disable-next-line arg-overflow
147 this.safeTransferFrom(from, to, pizzaId, "");
148 }
149
150 /**
151 * Transfère en toute sécurité la propriété d'un ID de jeton donné à une autre adresse
152 * Si l'adresse cible est un contrat, elle doit implémenter `onERC721Received`,
153 * qui est appelée lors d'un transfert sécurisé, et renvoyer la valeur magique
154 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
155 * sinon, le transfert est annulé.
156 */
157 function safeTransferFrom(
158 address from,
159 address to,
160 uint256 pizzaId,
161 bytes memory _data
162 ) public {
163 this.transferFrom(from, to, pizzaId);
164 require(_checkOnERC721Received(from, to, pizzaId, _data), "Doit implémenter onERC721Received.");
165 }
166
167 /**
168 * Fonction interne pour invoquer `onERC721Received` sur une adresse cible
169 * L'appel n'est pas exécuté si l'adresse cible n'est pas un contrat
170 */
171 function _checkOnERC721Received(
172 address from,
173 address to,
174 uint256 pizzaId,
175 bytes memory _data
176 ) internal returns (bool) {
177 if (!isContract(to)) {
178 return true;
179 }
180
181 bytes4 retval = IERC721Receiver(to).onERC721Received(
182 msg.sender,
183 from,
184 pizzaId,
185 _data
186 );
187 return (retval == _ERC721_RECEIVED);
188 }
189
190 // Brûle une Pizza - détruit complètement le jeton
191 // Le modificateur de fonction `external` signifie que cette fonction
192 // fait partie de l'interface du contrat et que d'autres contrats peuvent l'appeler
193 function burn(uint256 _pizzaId) external {
194 require(msg.sender != address(0), "Adresse non valide.");
195 require(_exists(_pizzaId), "La pizza n'existe pas.");
196 require(_isApprovedOrOwner(msg.sender, _pizzaId), "L'adresse n'est pas approuvée.");
197
198 ownerPizzaCount[msg.sender] = SafeMath.sub(
199 ownerPizzaCount[msg.sender],
200 1
201 );
202 pizzaToOwner[_pizzaId] = address(0);
203 }
204
205 // Renvoie le nombre de Pizzas par adresse
206 function balanceOf(address _owner) public view returns (uint256 _balance) {
207 return ownerPizzaCount[_owner];
208 }
209
210 // Renvoie le propriétaire de la Pizza trouvé par ID
211 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
212 address owner = pizzaToOwner[_pizzaId];
213 require(owner != address(0), "ID de Pizza non valide.");
214 return owner;
215 }
216
217 // Approuve une autre adresse pour transférer la propriété de la Pizza
218 function approve(address _to, uint256 _pizzaId) public {
219 require(msg.sender == pizzaToOwner[_pizzaId], "Doit être le propriétaire de la Pizza.");
220 pizzaApprovals[_pizzaId] = _to;
221 emit Approval(msg.sender, _to, _pizzaId);
222 }
223
224 // Renvoie l'adresse approuvée pour une Pizza spécifique
225 function getApproved(uint256 _pizzaId)
226 public
227 view
228 returns (address operator)
229 {
230 require(_exists(_pizzaId), "La pizza n'existe pas.");
231 return pizzaApprovals[_pizzaId];
232 }
233
234 /**
235 * Fonction privée pour effacer l'approbation actuelle d'un ID de jeton donné
236 * Annule si l'adresse donnée n'est pas en effet le propriétaire du jeton
237 */
238 function _clearApproval(address owner, uint256 _pizzaId) private {
239 require(pizzaToOwner[_pizzaId] == owner, "Doit être le propriétaire de la pizza.");
240 require(_exists(_pizzaId), "La pizza n'existe pas.");
241 if (pizzaApprovals[_pizzaId] != address(0)) {
242 pizzaApprovals[_pizzaId] = address(0);
243 }
244 }
245
246 /*
247 * Définit ou annule l'approbation d'un opérateur donné
248 * Un opérateur est autorisé à transférer tous les jetons de l'expéditeur en leur nom
249 */
250 function setApprovalForAll(address to, bool approved) public {
251 require(to != msg.sender, "Impossible d'approuver sa propre adresse");
252 operatorApprovals[msg.sender][to] = approved;
253 emit ApprovalForAll(msg.sender, to, approved);
254 }
255
256 // Indique si un opérateur est approuvé par un propriétaire donné
257 function isApprovedForAll(address owner, address operator)
258 public
259 view
260 returns (bool)
261 {
262 return operatorApprovals[owner][operator];
263 }
264
265 // Prend la propriété de la Pizza - uniquement pour les utilisateurs approuvés
266 function takeOwnership(uint256 _pizzaId) public {
267 require(_isApprovedOrOwner(msg.sender, _pizzaId), "L'adresse n'est pas approuvée.");
268 address owner = this.ownerOf(_pizzaId);
269 this.transferFrom(owner, msg.sender, _pizzaId);
270 }
271
272 // Vérifie si la Pizza existe
273 function _exists(uint256 pizzaId) internal view returns (bool) {
274 address owner = pizzaToOwner[pizzaId];
275 return owner != address(0);
276 }
277
278 // Vérifie si l'adresse est propriétaire ou est approuvée pour transférer la Pizza
279 function _isApprovedOrOwner(address spender, uint256 pizzaId)
280 internal
281 view
282 returns (bool)
283 {
284 address owner = pizzaToOwner[pizzaId];
285 // Disable solium check because of
286 // https://github.com/duaraghav8/Solium/issues/175
287 // solium-disable-next-line operator-whitespace
288 return (spender == owner ||
289 this.getApproved(pizzaId) == spender ||
290 this.isApprovedForAll(owner, spender));
291 }
292
293 // Vérifie si la Pizza est unique et n'existe pas encore
294 modifier isUnique(string memory _name, uint256 _dna) {
295 bool result = true;
296 for (uint256 i = 0; i < pizzas.length; i++) {
297 if (
298 keccak256(abi.encodePacked(pizzas[i].name)) ==
299 keccak256(abi.encodePacked(_name)) &&
300 pizzas[i].dna == _dna
301 ) {
302 result = false;
303 }
304 }
305 require(result, "Une pizza avec ce nom existe déjà.");
306 _;
307 }
308
309 // Renvoie si l'adresse cible est un contrat
310 function isContract(address account) internal view returns (bool) {
311 uint256 size;
312 // Actuellement, il n'y a pas de meilleure façon de vérifier s'il y a un contrat à une adresse
313 // que de vérifier la taille du code à cette adresse.
314 // Voir https://ethereum.stackexchange.com/a/14016/36603
315 // pour plus de détails sur son fonctionnement.
316 // TODO Vérifier à nouveau avant la sortie de Serenity, car toutes les adresses seront
317 // alors des contrats.
318 // solium-disable-next-line security/no-inline-assembly
319 assembly {
320 size := extcodesize(account)
321 }
322 return size > 0;
323 }
324}
Afficher tout

En savoir plus

Consultez la documentation Solidity et Vyper pour une vue d'ensemble plus complète des contrats intelligents :

Cet article vous a été utile ?