Solidity - Guide rapide

Solidity est un langage de programmation de haut niveau orienté contrat pour la mise en œuvre de contrats intelligents. La solidité est fortement influencée par C ++, Python et JavaScript et a été conçue pour cibler la machine virtuelle Ethereum (EVM).

Solidity est de type statique, prend en charge l'héritage, les bibliothèques et les langages de programmation de types complexes définis par l'utilisateur.

Vous pouvez utiliser Solidity pour créer des contrats pour des utilisations telles que le vote, le financement participatif, les enchères à l'aveugle et les portefeuilles multi-signatures.

Qu'est-ce que Ethereum?

Ethereum est un ie décentralisé. plateforme blockchain qui exécute des contrats intelligents, c'est-à-dire des applications qui fonctionnent exactement comme programmé sans aucune possibilité de temps d'arrêt, de censure, de fraude ou d'interférence de tiers.

La machine virtuelle Ethereum (EVM)

La machine virtuelle Ethereum, également connue sous le nom d'EVM, est l'environnement d'exécution des contrats intelligents dans Ethereum. La machine virtuelle Ethereum se concentre sur la sécurité et l'exécution de code non approuvé par des ordinateurs du monde entier.

L'EVM s'est spécialisé dans la prévention des attaques par déni de service et s'assure que les programmes n'ont pas accès à l'état de l'autre, garantissant que la communication peut être établie sans aucune interférence potentielle.

La machine virtuelle Ethereum a été conçue pour servir d'environnement d'exécution pour les contrats intelligents basés sur Ethereum.

Qu'est-ce que Smart Contract?

Un contrat intelligent est un protocole informatique destiné à faciliter, vérifier ou appliquer numériquement la négociation ou l'exécution d'un contrat. Les contrats intelligents permettent la réalisation de transactions crédibles sans tiers. Ces transactions sont traçables et irréversibles.

Le concept de contrats intelligents a été proposé pour la première fois par Nick Szabo en 1994. Szabo est un juriste et cryptographe connu pour avoir jeté les bases de la monnaie numérique.

C'est bien si vous ne comprenez pas Smart Contract pour le moment, nous reviendrons plus en détail plus tard.

Ce chapitre explique comment configurer le compilateur Solidity sur une machine CentOS. Si vous n'avez pas de machine Linux, vous pouvez utiliser notre compilateur en ligne pour les petits contrats et pour apprendre rapidement Solidity.

Méthode 1 - npm / Node.js

C'est le moyen le plus rapide d'installer le compilateur Solidity sur votre machine CentoS. Nous avons les étapes suivantes pour installer Solidity Compiler -

Installez Node.js

Assurez-vous d'abord que node.js est disponible sur votre machine CentOS. S'il n'est pas disponible, installez-le à l'aide des commandes suivantes -

# First install epel-release
$sudo yum install epel-release

# Now install nodejs
$sudo yum install nodejs

# Next install npm (Nodejs Package Manager )
$sudo yum install npm

# Finally verify installation
$npm --version

Si tout a été installé, vous verrez une sortie quelque chose comme ceci -

3.10.10

Installer solc

Une fois que vous avez installé le gestionnaire de packages Node.js, vous pouvez procéder à l'installation du compilateur Solidity comme ci-dessous -

$sudonpm install -g solc

La commande ci-dessus installera le programme solcjs et le rendra disponible globalement sur tout le système. Vous pouvez maintenant tester votre compilateur Solidity en émettant la commande suivante -

$solcjs-version

Si tout se passe bien, cela imprimera quelque chose comme suit -

0.5.2+commit.1df8f40c.Emscripten.clang

Vous êtes maintenant prêt à utiliser solcjs qui a moins de fonctionnalités que le compilateur Solidity standard, mais cela vous donnera un bon point de départ.

Méthode 2 - Image Docker

Vous pouvez extraire une image Docker et commencer à l'utiliser pour commencer la programmation Solidity. Voici les étapes simples. Voici la commande pour extraire une image Solidity Docker.

$docker pull ethereum/solc:stable

Une fois qu'une image docker est téléchargée, nous pouvons la vérifier à l'aide de la commande suivante.

$docker run ethereum/solc:stable-version

Cela imprimera quelque chose comme suit -

$ docker run ethereum/solc:stable -version

solc, the solidity compiler commandlineinterfaceVersion: 0.5.2+commit.1df8f40c.Linux.g++

Méthode 3: Installation des packages binaires

Si vous êtes prêt à installer un compilateur complet sur votre machine Linux, veuillez consulter le site Web officiel Installer le compilateur Solidity.

Un fichier source Solidity peut contenir un nombre illimité de définitions de contrat, de directives d'importation et de directives pragma.

Commençons par un simple fichier source de Solidity. Voici un exemple de fichier Solidity -

pragma solidity >=0.4.0 <0.6.0;
contract SimpleStorage {
   uint storedData;
   function set(uint x) public {
      storedData = x;
   }
   function get() public view returns (uint) {
      return storedData;
   }
}

Pragma

La première ligne est une directive pragma qui indique que le code source est écrit pour Solidity version 0.4.0 ou tout autre élément plus récent qui ne rompt pas les fonctionnalités jusqu'à, mais non compris, la version 0.6.0.

Une directive pragma est toujours locale dans un fichier source et si vous importez un autre fichier, le pragma de ce fichier ne s'appliquera pas automatiquement au fichier d'importation.

Donc, un pragma pour un fichier qui ne sera pas compilé avant la version 0.4.0 et qui ne fonctionnera pas non plus sur un compilateur à partir de la version 0.5.0 sera écrit comme suit -

pragma solidity ^0.4.0;

Ici, la deuxième condition est ajoutée en utilisant ^.

Contrat

Un contrat Solidity est un ensemble de code (ses fonctions) et de données (son état) qui réside à une adresse spécifique sur la chaîne Ethereumblockchain.

La ligne uintstoredData déclare une variable d'état appelée storedata de type uint et les fonctions set et get peuvent être utilisées pour modifier ou récupérer la valeur de la variable.

Importer des fichiers

Bien que l'exemple ci-dessus n'ait pas d'instruction d'importation, Solidity prend en charge les instructions d'importation très similaires à celles disponibles en JavaScript.

L'instruction suivante importe tous les symboles globaux de "filename".

import "filename";

L'exemple suivant crée un nouveau symbole global symbolName dont les membres sont tous les symboles globaux de "filename".

import * as symbolName from "filename";

Pour importer un fichier x depuis le même répertoire que le fichier actuel, utilisez import "./x" comme x ;. Si vous utilisez import "x" comme x; à la place, un fichier différent pourrait être référencé dans un "répertoire d'inclusion" global.

Mots clés réservés

Voici les mots-clés réservés dans Solidity -

abstrait après alias appliquer
auto Cas capture copie de
défaut définir final immuable
met en oeuvre dans en ligne laisser
macro rencontre mutable nul
de passer outre partiel promettre
référence relocalisable scellé taille de
statique les soutiens commutateur essayer
typedef Type de décoché

Nous utilisons Remix IDE pour compiler et exécuter notre base Solidity Code.

Step 1 - Copiez le code donné dans la section Code Remix IDE.

Exemple

pragma solidity ^0.5.0;
contract SolidityTest {
   constructor() public{
   }
   function getResult() public view returns(uint){
      uint a = 1;
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

Step 2 - Sous l'onglet Compiler, cliquez sur Start to Compile bouton.

Step 3 - Sous l'onglet Exécuter, cliquez sur Deploy bouton.

Step 4 - Sous l'onglet Exécuter, sélectionnez SolidityTest at 0x... dans la liste déroulante.

Step 5 - Cliquez getResult Bouton pour afficher le résultat.

Production

0: uint256: 3

Solidity prend en charge les commentaires de style C et C ++, ainsi -

  • Tout texte entre un // et la fin d'une ligne est traité comme un commentaire et est ignoré par Solidity Compiler.

  • Tout texte entre les caractères / * et * / est traité comme un commentaire. Cela peut s'étendre sur plusieurs lignes.

Exemple

L'exemple suivant montre comment utiliser les commentaires dans Solidity.

function getResult() public view returns(uint){
   // This is a comment. It is similar to comments in C++

   /*
      * This is a multi-line comment in solidity
      * It is very similar to comments in C Programming
   */
   uint a = 1;
   uint b = 2;
   uint result = a + b;
   return result;
}

Lors de l'écriture d'un programme dans n'importe quelle langue, vous devez utiliser diverses variables pour stocker diverses informations. Les variables ne sont rien d'autre que des emplacements de mémoire réservés pour stocker des valeurs. Cela signifie que lorsque vous créez une variable, vous réservez de l'espace en mémoire.

Vous pouvez souhaiter stocker des informations de différents types de données comme des caractères, des caractères larges, des nombres entiers, des virgule flottante, des virgule flottante double, des valeurs booléennes, etc. En fonction du type de données d'une variable, le système d'exploitation alloue de la mémoire et décide de ce qui peut être stocké dans le mémoire réservée.

Types de valeur

Solidity offre au programmeur un riche assortiment de types de données intégrés et définis par l'utilisateur. Le tableau suivant répertorie sept types de données de base C ++ -

Type Mot-clé Valeurs
Booléen booléen vrai faux
Entier int / uint Entiers signés et non signés de différentes tailles.
Entier int8 à int256 Signé int de 8 bits à 256 bits. int256 est identique à int.
Entier uint8 à uint256 Un entier non signé de 8 bits à 256 bits. uint256 est identique à uint.
Numéros à virgule fixe fixe / non fixé Numéros à virgule fixe signés et non signés de différentes tailles.
Numéros à virgule fixe fixe / non fixé Numéros à virgule fixe signés et non signés de différentes tailles.
Numéros à virgule fixe fixedMxN Nombre à virgule fixe signé où M représente le nombre de bits pris par type et N représente les points décimaux. M doit être divisible par 8 et va de 8 à 256. N peut être compris entre 0 et 80. fixed est identique à fixed128x18.
Numéros à virgule fixe ufixedMxN Nombre à virgule fixe non signé où M représente le nombre de bits pris par type et N représente les points décimaux. M doit être divisible par 8 et va de 8 à 256. N peut être compris entre 0 et 80. ufixed est identique à ufixed128x18.

adresse

address contient la valeur de 20 octets représentant la taille d'une adresse Ethereum. Une adresse peut être utilisée pour obtenir le solde en utilisant la méthode .balance et peut être utilisée pour transférer le solde à une autre adresse en utilisant la méthode .transfer.

address x = 0x212;
address myAddress = this;
if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);

Solidity prend en charge trois types de variables.

  • State Variables - Variables dont les valeurs sont stockées en permanence dans un stockage de contrat.

  • Local Variables - Variables dont les valeurs sont présentes jusqu'à ce que la fonction s'exécute.

  • Global Variables - Des variables spéciales existent dans l'espace de noms global utilisé pour obtenir des informations sur la blockchain.

Solidity est un langage typé statiquement, ce qui signifie que l'état ou le type de variable locale doit être spécifié lors de la déclaration. Chaque variable déclarée a toujours une valeur par défaut basée sur son type. Il n'y a pas de concept de "non défini" ou "nul".

État variable

Variables dont les valeurs sont stockées en permanence dans un stockage de contrat.

pragma solidity ^0.5.0;
contract SolidityTest {
   uint storedData;      // State variable
   constructor() public {
      storedData = 10;   // Using State variable
   }
}

Variable locale

Variables dont les valeurs ne sont disponibles que dans une fonction où elle est définie. Les paramètres de fonction sont toujours locaux à cette fonction.

pragma solidity ^0.5.0;
contract SolidityTest {
   uint storedData; // State variable
   constructor() public {
      storedData = 10;   
   }
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return result; //access the local variable
   }
}

Exemple

pragma solidity ^0.5.0;
contract SolidityTest {
   uint storedData; // State variable
   constructor() public {
      storedData = 10;   
   }
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return storedData; //access the state variable
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: uint256: 10

Variables globales

Ce sont des variables spéciales qui existent dans l'espace de travail global et fournissent des informations sur la blockchain et les propriétés de transaction.

Nom Retour
blockhash (uint blockNumber) renvoie (octets32) Hash du bloc donné - ne fonctionne que pour 256 blocs les plus récents, à l'exclusion des blocs actuels
block.coinbase (adresse payable) Adresse actuelle du mineur de bloc
bloquer la difficulté (uint) Difficulté actuelle du bloc
block.gaslimit (uint) Limite de gaz de blocage actuelle
block.number (uint) Numéro de bloc actuel
block.timestamp (uint) Horodatage du bloc actuel en secondes depuis l'époque Unix
gasleft () renvoie (uint256) Gaz restant
msg.data (octets de données d'appel) Données d'appel complètes
msg.sender (adresse payable) Expéditeur du message (appelant actuel)
msg.sig (octets4) Quatre premiers octets des données d'appel (identificateur de fonction)
msg.value (uint) Nombre de wei envoyés avec le message
maintenant (uint) Horodatage du bloc actuel
tx.gasprice (uint) Prix ​​du gaz de la transaction
tx.origin (adresse payable) Expéditeur de la transaction

Noms des variables de solidité

Lorsque vous nommez vos variables dans Solidity, gardez à l'esprit les règles suivantes.

  • Vous ne devez utiliser aucun des mots clés réservés Solidity comme nom de variable. Ces mots-clés sont mentionnés dans la section suivante. Par exemple, les noms de variable break ou booléenne ne sont pas valides.

  • Les noms de variables de solidité ne doivent pas commencer par un chiffre (0-9). Ils doivent commencer par une lettre ou un caractère de soulignement. Par exemple, 123test est un nom de variable non valide mais _123test est un nom valide.

  • Les noms des variables Solidity sont sensibles à la casse. Par exemple, le nom et le nom sont deux variables différentes.

La portée des variables locales est limitée à la fonction dans laquelle elles sont définies, mais les variables d'état peuvent avoir trois types de portées.

  • Public- Les variables d'état publiques sont accessibles en interne ainsi que via des messages. Pour une variable d'état publique, une fonction getter automatique est générée.

  • Internal - Les variables d'état internes ne sont accessibles qu'en interne à partir du contrat en cours ou du contrat qui en dérive sans l'utiliser.

  • Private - Les variables d'état privées ne sont accessibles qu'en interne à partir du contrat actuel, elles ne sont pas définies dans le contrat dérivé de celui-ci.

Exemple

pragma solidity ^0.5.0;
contract C {
   uint public data = 30;
   uint internal iData= 10;
   
   function x() public returns (uint) {
      data = 3; // internal access
      return data;
   }
}
contract Caller {
   C c = new C();
   function f() public view returns (uint) {
      return c.data(); //external access
   }
}
contract D is C {
   function y() public returns (uint) {
      iData = 3; // internal access
      return iData;
   }
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return storedData; //access the state variable
   }
}

Qu'est-ce qu'un opérateur?

Prenons une expression simple 4 + 5 is equal to 9. Ici 4 et 5 sont appelésoperands et '+' est appelé le operator. Solidity prend en charge les types d'opérateurs suivants.

  • Opérateurs arithmétiques
  • Opérateurs de comparaison
  • Opérateurs logiques (ou relationnels)
  • Opérateurs d'affectation
  • Opérateurs conditionnels (ou ternaires)

Jetons un coup d'œil sur tous les opérateurs un par un.

Opérateurs arithmétiques

Solidity prend en charge les opérateurs arithmétiques suivants -

Supposons que la variable A vaut 10 et la variable B 20, alors -

Montrer l'exemple

Sr.No. Opérateur et description
1

+ (Addition)

Ajoute deux opérandes

Ex: A + B donnera 30

2

- (Subtraction)

Soustrait le deuxième opérande du premier

Ex: A - B donnera -10

3

* (Multiplication)

Multiplier les deux opérandes

Ex: A * B donnera 200

4

/ (Division)

Divisez le numérateur par le dénominateur

Ex: B / A donnera 2

5

% (Modulus)

Produit le reste d'une division entière

Ex: B% A donnera 0

6

++ (Increment)

Augmente une valeur entière de un

Ex: A ++ donnera 11

sept

-- (Decrement)

Diminue une valeur entière de un

Ex: A-- donnera 9

Opérateurs de comparaison

Solidity prend en charge les opérateurs de comparaison suivants -

Supposons que la variable A vaut 10 et la variable B 20, alors -

Montrer l'exemple

Sr.No. Opérateur et description
1

= = (Equal)

Vérifie si la valeur de deux opérandes est égale ou non, si oui, la condition devient vraie.

Ex: (A == B) n'est pas vrai.

2

!= (Not Equal)

Vérifie si la valeur de deux opérandes est égale ou non, si les valeurs ne sont pas égales, la condition devient vraie.

Ex: (A! = B) est vrai.

3

> (Greater than)

Vérifie si la valeur de l'opérande gauche est supérieure à la valeur de l'opérande droit, si oui, la condition devient vraie.

Ex: (A> B) n'est pas vrai.

4

< (Less than)

Vérifie si la valeur de l'opérande gauche est inférieure à la valeur de l'opérande droit, si oui, la condition devient vraie.

Ex: (A <B) est vrai.

5

>= (Greater than or Equal to)

Vérifie si la valeur de l'opérande gauche est supérieure ou égale à la valeur de l'opérande droit, si oui, la condition devient vraie.

Ex: (A> = B) n'est pas vrai.

6

<= (Less than or Equal to)

Vérifie si la valeur de l'opérande gauche est inférieure ou égale à la valeur de l'opérande droit, si oui, la condition devient vraie.

Ex: (A <= B) est vrai.

Opérateurs logiques

Solidity prend en charge les opérateurs logiques suivants -

Supposons que la variable A vaut 10 et la variable B 20, alors -

Montrer l'exemple

Sr.No. Opérateur et description
1

&& (Logical AND)

Si les deux opérandes sont différents de zéro, la condition devient vraie.

Ex: (A && B) est vrai.

2

|| (Logical OR)

Si l'un des deux opérandes est différent de zéro, la condition devient vraie.

Ex: (A || B) est vrai.

3

! (Logical NOT)

Inverse l'état logique de son opérande. Si une condition est vraie, alors l'opérateur logique NOT la rendra fausse.

Ex:! (A && B) est faux.

Opérateurs au niveau du bit

Solidity prend en charge les opérateurs binaires suivants -

Supposons que la variable A vaut 2 et la variable B vaut 3, alors -

Montrer l'exemple

Sr.No. Opérateur et description
1

& (Bitwise AND)

Il effectue une opération booléenne AND sur chaque bit de ses arguments entiers.

Ex: (A & B) est égal à 2.

2

| (BitWise OR)

Il effectue une opération booléenne OU sur chaque bit de ses arguments entiers.

Ex: (A | B) vaut 3.

3

^ (Bitwise XOR)

Il effectue une opération OU exclusive booléenne sur chaque bit de ses arguments entiers. OU exclusif signifie que l'opérande un est vrai ou que l'opérande deux est vrai, mais pas les deux.

Ex: (A ^ B) vaut 1.

4

~ (Bitwise Not)

C'est un opérateur unaire et fonctionne en inversant tous les bits de l'opérande.

Ex: (~ B) est -4.

5

<< (Left Shift)

Il déplace tous les bits de son premier opérande vers la gauche du nombre de places spécifié dans le deuxième opérande. Les nouveaux bits sont remplis de zéros. Décaler une valeur vers la gauche d'une position équivaut à la multiplier par 2, déplacer deux positions équivaut à multiplier par 4, et ainsi de suite.

Ex: (A << 1) vaut 4.

6

>> (Right Shift)

Opérateur de décalage binaire vers la droite. La valeur de l'opérande de gauche est déplacée vers la droite du nombre de bits spécifié par l'opérande de droite.

Ex: (A >> 1) vaut 1.

sept

>>> (Right shift with Zero)

Cet opérateur est exactement comme l'opérateur >>, sauf que les bits décalés à gauche sont toujours nuls.

Ex: (A >>> 1) vaut 1.

Opérateurs d'affectation

Solidity prend en charge les opérateurs d'affectation suivants -

Montrer l'exemple

Sr.No. Opérateur et description
1

= (Simple Assignment )

Attribue des valeurs de l'opérande de droite à l'opérande de gauche

Ex: C = A + B attribuera la valeur de A + B à C

2

+= (Add and Assignment)

Il ajoute l'opérande droit à l'opérande gauche et affecte le résultat à l'opérande gauche.

Ex: C + = A équivaut à C = C + A

3

−= (Subtract and Assignment)

Il soustrait l'opérande droit de l'opérande gauche et affecte le résultat à l'opérande gauche.

Ex: C - = A équivaut à C = C - A

4

*= (Multiply and Assignment)

Il multiplie l'opérande droit par l'opérande gauche et affecte le résultat à l'opérande gauche.

Ex: C * = A équivaut à C = C * A

5

/= (Divide and Assignment)

Il divise l'opérande de gauche par l'opérande de droite et affecte le résultat à l'opérande de gauche.

Ex: C / = A équivaut à C = C / A

6

%= (Modules and Assignment)

Il prend le module en utilisant deux opérandes et affecte le résultat à l'opérande de gauche.

Ex: C% = A équivaut à C = C% A

Note - La même logique s'applique aux opérateurs au niveau du bit, donc ils deviendront comme << =, >> =, >> =, & =, | = et ^ =.

Opérateur conditionnel (? :)

L'opérateur conditionnel évalue d'abord une expression pour une valeur vraie ou fausse, puis exécute l'une des deux instructions données en fonction du résultat de l'évaluation.

Montrer l'exemple

Sr.No. Opérateur et description
1

? : (Conditional )

Si la condition est vraie? Alors valeur X: Sinon valeur Y

Lors de la rédaction d'un contrat, vous pouvez rencontrer une situation où vous devez effectuer une action encore et encore. Dans de telles situations, vous devrez écrire des instructions de boucle pour réduire le nombre de lignes.

Solidity prend en charge toutes les boucles nécessaires pour réduire la pression de la programmation.

Sr. Non Boucles et description
1

Alors que la boucle

La boucle la plus élémentaire de Solidity est la boucle while qui sera abordée dans ce chapitre.

2

faire ... en boucle

La boucle do ... while est similaire à la boucle while sauf que le contrôle de condition se produit à la fin de la boucle.

3

Pour la boucle

La boucle for est la forme de boucle la plus compacte. Il comprend les trois parties importantes suivantes.

4

Contrôle de boucle

Solidity offre un contrôle total pour gérer les boucles et les instructions de commutation.

Lors de l'écriture d'un programme, il peut arriver que vous deviez en adopter un parmi un ensemble donné de chemins. Dans de tels cas, vous devez utiliser des instructions conditionnelles qui permettent à votre programme de prendre les bonnes décisions et d'exécuter les bonnes actions.

Solidity prend en charge les instructions conditionnelles qui sont utilisées pour effectuer différentes actions basées sur différentes conditions. Ici, nous allons expliquer leif..else déclaration.

Organigramme de if-else

L'organigramme suivant montre le fonctionnement de l'instruction if-else.

Solidity prend en charge les formes suivantes de if..else déclaration -

Sr. Non Déclarations et description
1

if déclaration

L'instruction if est l'instruction de contrôle fondamentale qui permet à Solidity de prendre des décisions et d'exécuter des instructions de manière conditionnelle.

2

if ... instruction else

L'instruction 'if ... else' est la prochaine forme d'instruction de contrôle qui permet à Solidity d'exécuter des instructions de manière plus contrôlée.

3

si ... sinon si ... déclaration.

L'instruction if ... else if ... est une forme avancée de if ... else qui permet à Solidity de prendre une décision correcte à partir de plusieurs conditions.

Solidity prend en charge le littéral String en utilisant à la fois des guillemets doubles (") et des guillemets simples ('). Il fournit une chaîne comme type de données pour déclarer une variable de type String.

pragma solidity ^0.5.0;

contract SolidityTest {
   string data = "test";
}

Dans l'exemple ci-dessus, "test" est une chaîne littérale et data est une variable chaîne. Une manière plus préférée consiste à utiliser des types d'octets au lieu de String car l'opération de chaîne nécessite plus de gaz que l'opération d'octet. Solidity fournit une conversion intégrée d'octets en chaîne et vice versa. Dans Solidity, nous pouvons facilement affecter un littéral String à une variable de type byte32. Solidity le considère comme un littéral byte32.

pragma solidity ^0.5.0;

contract SolidityTest {
   bytes32 data = "test";
}

Personnages de fuite

Sr.No. Caractère et description
1

\n

Démarre une nouvelle ligne.

2

\\

Antislash

3

\'

Simple citation

4

\"

Double citation

5

\b

Retour arrière

6

\f

Form Feed

sept

\r

Retour chariot

8

\t

Languette

9

\v

Onglet vertical

dix

\xNN

Représente la valeur hexadécimale et insère les octets appropriés.

11

\uNNNN

Représente la valeur Unicode et insère la séquence UTF-8.

Conversion d'octets en chaîne

Les octets peuvent être convertis en String à l'aide du constructeur string ().

bytes memory bstr = new bytes(10);
string message = string(bstr);

Exemple

Essayez le code suivant pour comprendre comment la chaîne fonctionne dans Solidity.

pragma solidity ^0.5.0;

contract SolidityTest {   
   constructor() public{       
   }
   function getResult() public view returns(string memory){
      uint a = 1; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }
   function integerToString(uint _i) internal pure 
      returns (string memory) {
      
      if (_i == 0) {
         return "0";
      }
      uint j = _i;
      uint len;
      
      while (j != 0) {
         len++;
         j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;
      
      while (_i != 0) {
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      return string(bstr);
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: string: 3

Array est une structure de données, qui stocke une collection séquentielle de taille fixe d'éléments du même type. Un tableau est utilisé pour stocker une collection de données, mais il est souvent plus utile de considérer un tableau comme une collection de variables du même type.

Au lieu de déclarer des variables individuelles, telles que nombre0, nombre1, ... et nombre99, vous déclarez une variable de tableau telle que des nombres et utilisez les nombres [0], les nombres [1] et ..., les nombres [99] pour représenter variables individuelles. Un élément spécifique d'un tableau est accessible par un index.

Dans Solidity, un tableau peut être de taille fixe au moment de la compilation ou de taille dynamique. Pour la baie de stockage, elle peut également avoir différents types d'éléments. Dans le cas d'un tableau de mémoire, le type d'élément ne peut pas être mappé et s'il doit être utilisé comme paramètre de fonction, le type d'élément doit être un type ABI.

Tous les tableaux sont constitués d'emplacements de mémoire contigus. L'adresse la plus basse correspond au premier élément et l'adresse la plus élevée au dernier élément.

Déclaration de tableaux

Pour déclarer un tableau de taille fixe dans Solidity, le programmeur spécifie le type des éléments et le nombre d'éléments requis par un tableau comme suit -

type arrayName [ arraySize ];

C'est ce qu'on appelle un tableau à une seule dimension. learraySize doit être une constante entière supérieure à zéro et typepeut être n'importe quel type de données Solidity valide. Par exemple, pour déclarer un tableau de 10 éléments appelé balance de type uint, utilisez cette instruction -

uint balance[10];

Pour déclarer un tableau de taille dynamique dans Solidity, le programmeur spécifie le type des éléments comme suit -

type[] arrayName;

Initialisation des tableaux

Vous pouvez initialiser les éléments du tableau Solidity un par un ou en utilisant une seule instruction comme suit -

uint balance[3] = [1, 2, 3];

Le nombre de valeurs entre accolades [] ne peut pas être supérieur au nombre d'éléments que nous déclarons pour le tableau entre crochets []. Voici un exemple pour affecter un seul élément du tableau -

Si vous omettez la taille du tableau, un tableau juste assez grand pour contenir l'initialisation est créé. Par conséquent, si vous écrivez -

uint balance[] = [1, 2, 3];

Vous allez créer exactement le même tableau que vous l'avez fait dans l'exemple précédent.

balance[2] = 5;

L'instruction ci-dessus attribue au numéro d'élément 3 rd dans le tableau la valeur 5.

Création de tableaux de mémoire dynamiques

Les tableaux de mémoire dynamiques sont créés à l'aide d'un nouveau mot-clé.

uint size = 3;
uint balance[] = new uint[](size);

Accès aux éléments de la baie

Un élément est accessible en indexant le nom du tableau. Cela se fait en plaçant l'index de l'élément entre crochets après le nom du tableau. Par exemple -

uint salary = balance[2];

La déclaration ci - dessus prendra 3 ème élément du tableau et affecter la valeur à la variable salaire. Voici un exemple, qui utilisera tous les trois concepts mentionnés ci-dessus à savoir. déclaration, affectation et accès aux tableaux -

Membres

  • length- length renvoie la taille du tableau. length peut être utilisé pour changer la taille du tableau dynamique en le définissant.

  • push- push permet d'ajouter un élément à un tableau de stockage dynamique à la fin. Il renvoie la nouvelle longueur du tableau.

Exemple

Essayez le code suivant pour comprendre le fonctionnement des tableaux dans Solidity.

pragma solidity ^0.5.0;

contract test {
   function testArray() public pure{
      uint len = 7; 
      
      //dynamic array
      uint[] memory a = new uint[](7);
      
      //bytes is same as byte[]
      bytes memory b = new bytes(len);
      
      assert(a.length == 7);
      assert(b.length == len);
      
      //access array variable
      a[6] = 8;
      
      //test array variable
      assert(a[6] == 8);
      
      //static array
      uint[3] memory c = [uint(1) , 2, 3];
      assert(c.length == 3);
   }
}

Les énumérations limitent une variable à l'une des rares valeurs prédéfinies. Les valeurs de cette liste énumérée sont appelées énumérations.

Avec l'utilisation d'énumérations, il est possible de réduire le nombre de bogues dans votre code.

Par exemple, si nous considérons une demande pour un magasin de jus de fruits frais, il serait possible de limiter la taille du verre à petite, moyenne et grande. Cela garantirait qu'il ne permettrait à personne de commander une taille autre que petite, moyenne ou grande.

Exemple

Essayez le code suivant pour comprendre le fonctionnement de l'énumération dans Solidity.

pragma solidity ^0.5.0;

contract test {
   enum FreshJuiceSize{ SMALL, MEDIUM, LARGE }
   FreshJuiceSize choice;
   FreshJuiceSize constant defaultChoice = FreshJuiceSize.MEDIUM;

   function setLarge() public {
      choice = FreshJuiceSize.LARGE;
   }
   function getChoice() public view returns (FreshJuiceSize) {
      return choice;
   }
   function getDefaultChoice() public pure returns (uint) {
      return uint(defaultChoice);
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Premier clic setLarge Bouton pour définir la valeur sur LARGE puis cliquez sur getChoice pour obtenir le choix sélectionné.

Production

uint8: 2

Cliquez sur getDefaultChoice Bouton pour obtenir le choix par défaut.

Production

uint256: 1

Les types Struct sont utilisés pour représenter un enregistrement. Supposons que vous souhaitiez garder une trace de vos livres dans une bibliothèque. Vous souhaiterez peut-être suivre les attributs suivants pour chaque livre -

  • Title
  • Author
  • Subject
  • ID du livre

Définition d'une structure

Pour définir une structure, vous devez utiliser le structmot-clé. Le mot-clé struct définit un nouveau type de données, avec plus d'un membre. Le format de l'instruction struct est le suivant -

struct struct_name { 
   type1 type_name_1;
   type2 type_name_2;
   type3 type_name_3;
}

Exemple

struct Book { 
   string title;
   string author;
   uint book_id;
}

Accéder à une structure et à sa variable

Pour accéder à n'importe quel membre d'une structure, nous utilisons l'opérateur d'accès aux membres (.). L'opérateur d'accès au membre est codé comme un point entre le nom de la variable de structure et le membre de la structure auquel nous souhaitons accéder. Vous utiliseriez la structure pour définir des variables de type structure. L'exemple suivant montre comment utiliser une structure dans un programme.

Exemple

Essayez le code suivant pour comprendre comment les structures fonctionnent dans Solidity.

pragma solidity ^0.5.0;

contract test {
   struct Book { 
      string title;
      string author;
      uint book_id;
   }
   Book book;

   function setBook() public {
      book = Book('Learn Java', 'TP', 1);
   }
   function getBookId() public view returns (uint) {
      return book.book_id;
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Premier clic setBook Bouton pour définir la valeur sur LARGE puis cliquez sur getBookId pour obtenir l'identifiant du livre sélectionné.

Production

uint256: 1

Le mappage est un type de référence sous forme de tableaux et de structures. Voici la syntaxe pour déclarer un type de mappage.

mapping(_KeyType => _ValueType)

  • _KeyType- peut être n'importe quel type intégré plus des octets et une chaîne. Aucun type de référence ou objets complexes ne sont autorisés.

  • _ValueType - peut être de n'importe quel type.

Considérations

  • Le mappage ne peut avoir que le type de storage et sont généralement utilisés pour les variables d'état.

  • Le mappage peut être marqué comme public. Solidity crée automatiquement un getter pour cela.

Exemple

Essayez le code suivant pour comprendre le fonctionnement du type de mappage dans Solidity.

pragma solidity ^0.5.0;

contract LedgerBalance {
   mapping(address => uint) public balances;

   function updateBalance(uint newBalance) public {
      balances[msg.sender] = newBalance;
   }
}
contract Updater {
   function updateBalance() public returns (uint) {
      LedgerBalance ledgerBalance = new LedgerBalance();
      ledgerBalance.updateBalance(10);
      return ledgerBalance.balances(address(this));
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Premier clic updateBalance Bouton pour définir la valeur sur 10, puis regardez dans les journaux qui afficheront la sortie décodée comme -

Production

{
   "0": "uint256: 10"
}

La solidité permet une conversion implicite et explicite. Le compilateur Solidity permet une conversion implicite entre deux types de données à condition qu'aucune conversion implicite ne soit possible et qu'il n'y ait pas de perte d'informations. Par exemple, uint8 est convertible en uint16 mais int8 est convertible en uint256 car int8 peut contenir une valeur négative non autorisée dans uint256.

Conversion explicite

Nous pouvons convertir explicitement un type de données en un autre en utilisant la syntaxe du constructeur.

int8 y = -3;
uint x = uint(y);
//Now x = 0xfffff..fd == two complement representation of -3 in 256 bit format.

La conversion vers un type plus petit coûte des bits d'ordre supérieur.

uint32 a = 0x12345678;
uint16 b = uint16(a); // b = 0x5678

La conversion vers un type supérieur ajoute des bits de remplissage à gauche.

uint16 a = 0x1234;
uint32 b = uint32(a); // b = 0x00001234

La conversion en octets plus petits coûte des données d'ordre supérieur.

bytes2 a = 0x1234;
bytes1 b = bytes1(a); // b = 0x12

La conversion en octet plus grand ajoute des bits de remplissage à droite.

bytes2 a = 0x1234;
bytes4 b = bytes4(a); // b = 0x12340000

La conversion entre octets de taille fixe et int n'est possible que lorsque les deux sont de même taille.

bytes2 a = 0x1234;
uint32 b = uint16(a); // b = 0x00001234
uint32 c = uint32(bytes4(a)); // c = 0x12340000
uint8 d = uint8(uint16(a)); // d = 0x34
uint8 e = uint8(bytes1(a)); // e = 0x12

Les nombres hexadécimaux peuvent être affectés à n'importe quel type entier si aucune troncature n'est nécessaire.

uint8 a = 12; // no error
uint32 b = 1234; // no error
uint16 c = 0x123456; // error, as truncation required to 0x3456

Dans la solidité, nous pouvons utiliser wei, finney, szabo ou éther comme suffixe à un littéral à utiliser pour convertir diverses dénominations à base d'éther. L'unité la plus basse est wei et 1e12 représente 1 x 10 12 .

assert(1 wei == 1);
assert(1 szabo == 1e12);
assert(1 finney == 1e15);
assert(1 ether == 1e18);
assert(2 ether == 2000 fenny);

Unités de temps

Semblable à la devise, Solidity a des unités de temps où l'unité la plus basse est la seconde et nous pouvons utiliser les secondes, les minutes, les heures, les jours et les semaines comme suffixe pour désigner le temps.

assert(1 seconds == 1);
assert(1 minutes == 60 seconds);
assert(1 hours == 60 minutes);
assert(1 day == 24 hours);
assert(1 week == 7 days);

Les variables spéciales sont des variables disponibles dans le monde entier et fournissent des informations sur la blockchain. Voici la liste des variables spéciales -

Sr.No. Variable spéciale et description
1

blockhash(uint blockNumber) returns (bytes32)

Hash du bloc donné - ne fonctionne que pour les 256 blocs les plus récents, à l'exclusion des blocs actuels.

2

block.coinbase (address payable)

Adresse actuelle du mineur de bloc.

3

block.difficulty (uint)

difficulté actuelle du bloc.

4

block.gaslimit (uint)

Limite de gaz de blocage actuelle.

5

block.number (uint)

Numéro de bloc actuel.

6

block.timestamp

Horodatage du bloc actuel en secondes depuis l'époque Unix.

sept

gasleft() returns (uint256)

Gaz restant.

8

msg.data (bytes calldata)

Données d'appel complètes.

9

msg.sender (address payable)

Expéditeur du message (appel en cours).

dix

msg.sig (bytes4)

Quatre premiers octets des données d'appel (c.-à-d. Identificateur de fonction)

11

msg.value (uint)

Nombre de wei envoyés avec le message.

12

now (uint)

Horodatage du bloc actuel (alias pour block.timestamp).

13

tx.gasprice (uint)

Prix ​​du gaz de la transaction.

14

tx.origin (address payable)

Expéditeur de la transaction (chaîne d'appel complète).

Exemple

Essayez le code suivant pour voir l'utilisation de msg, une variable spéciale pour obtenir l'adresse de l'expéditeur dans Solidity.

pragma solidity ^0.5.0;

contract LedgerBalance {
   mapping(address => uint) public balances;

   function updateBalance(uint newBalance) public {
      balances[msg.sender] = newBalance;
   }
}
contract Updater {
   function updateBalance() public returns (uint) {
      LedgerBalance ledgerBalance = new LedgerBalance();
      ledgerBalance.updateBalance(10);
      return ledgerBalance.balances(address(this));
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Premier clic updateBalance Bouton pour définir la valeur sur 10, puis regardez dans les journaux qui afficheront la sortie décodée comme -

Production

{
   "0": "uint256: 10"
}

Le Guide de style aide à maintenir la mise en page du code cohérente et à rendre le code plus lisible. Voici les meilleures pratiques à suivre lors de la rédaction de contrats avec Solidity.

Disposition du code

  • Indentation- Utilisez 4 espaces au lieu de tabulation pour maintenir le niveau d'indentation. Évitez de mélanger les espaces avec les onglets.

  • Two Blank Lines Rule - Utilisez 2 lignes vides entre deux définitions de contrat.

pragma solidity ^0.5.0;

contract LedgerBalance {
   //...
}
contract Updater {
   //...
}
  • One Blank Line Rule- Utilisez 1 ligne vide entre deux fonctions. En cas de déclaration uniquement, pas besoin de lignes vierges.

pragma solidity ^0.5.0;

contract A {
   function balance() public pure;
   function account() public pure;
}
contract B is A {
   function balance() public pure {
      // ...
   }
   function account() public pure {
      // ...
   }
}
  • Maximum Line Length - Une seule ligne ne doit pas traverser 79 caractères afin que les lecteurs puissent facilement analyser le code.

  • Wrapping rules- Le premier argument est dans une nouvelle ligne sans ouvrir les parenthèses. Utilisez un seul retrait par argument. Élément de terminaison); devrait être le dernier.

function_with_a_long_name(
   longArgument1,
   longArgument2,
   longArgument3
);
variable = function_with_a_long_name(
   longArgument1,
   longArgument2,
   longArgument3
);
event multipleArguments(
   address sender,
   address recipient,
   uint256 publicKey,
   uint256 amount,
   bytes32[] options
);
MultipleArguments(
   sender,
   recipient,
   publicKey,
   amount,
   options
);
  • Source Code Encoding - Le codage UTF-8 ou ASCII doit être utilisé de préférence.

  • Imports - Les instructions d'importation doivent être placées en haut du fichier juste après la déclaration de pragma.

  • Order of Functions - Les fonctions doivent être regroupées selon leur visibilité.

pragma solidity ^0.5.0;

contract A {
   constructor() public {
      // ...
   }
   function() external {
      // ...
   }

   // External functions
   // ...

   // External view functions
   // ...

   // External pure functions 
   // ...

   // Public functions
   // ...

   // Internal functions
   // ...

   // Private functions
   // ...
}
  • Avoid extra whitespaces - Évitez les espaces immédiatement entre parenthèses, crochets ou accolades.

  • Control structures- Les accolades doivent s'ouvrir sur la même ligne que la déclaration. Fermer sur leur propre ligne en conservant la même indentation. Utilisez un espace avec accolade ouvrante.

pragma solidity ^0.5.0;

contract Coin {
   struct Bank {
      address owner;
      uint balance;
   }
}
if (x < 3) {
   x += 1;
} else if (x > 7) {
   x -= 1;
} else {
   x = 5;
}
if (x < 3)
   x += 1;
else
   x -= 1;
  • Function Declaration- Utilisez la règle ci-dessus pour les accolades. Ajoutez toujours une étiquette de visibilité. L'étiquette de visibilité doit venir avant tout modificateur personnalisé.

function kill() public onlyowner {
   selfdestruct(owner);
}
  • Mappings - Évitez les espaces lors de la déclaration des variables de mappage.

mapping(uint => uint) map;
mapping(address => bool) registeredAddresses;
mapping(uint => mapping(bool => Data[])) public data;
mapping(uint => mapping(uint => s)) data;
  • Variable declaration - Évitez les espaces lors de la déclaration des variables de tableau.

uint[] x;  // not unit [] x;
  • String declaration - Utilisez des guillemets doubles pour déclarer une chaîne au lieu de guillemets simples.

str = "foo";
str = "Hamlet says, 'To be or not to be...'";

Ordre de disposition

Les éléments doivent être mis en page dans l'ordre suivant.

  • Déclarations Pragma

  • Importer des déclarations

  • Interfaces

  • Libraries

  • Contracts

Dans les interfaces, les bibliothèques ou les contrats, la commande doit être comme -

  • Déclarations de type

  • Variables d'état

  • Events

  • Functions

Conventions de nommage

  • Le contrat et la bibliothèque doivent être nommés en utilisant le style CapWords. Par exemple, SmartContract, Owner, etc.

  • Le nom du contrat et de la bibliothèque doit correspondre à leurs noms de fichiers.

  • En cas de plusieurs contrats / bibliothèques dans un fichier, utilisez le nom du contrat / bibliothèque principal.

Owned.sol

pragma solidity ^0.5.0;

// Owned.sol
contract Owned {
   address public owner;
   constructor() public {
      owner = msg.sender;
   }
   modifier onlyOwner {
      //....
   }
   function transferOwnership(address newOwner) public onlyOwner {
      //...
   }
}

Congress.sol

pragma solidity ^0.5.0;

// Congress.sol
import "./Owned.sol";

contract Congress is Owned, TokenRecipient {
   //...
}
  • Noms de structure

    - Utilisez le style CapWords comme SmartCoin.

  • Noms d'événements

    - Utilisez le style CapWords comme Dépôt, AfterTransfer.

  • Noms des fonctions

    - Utilisez le style mixedCase comme initateSupply.

  • Variables locales et d'état

    - Utilisez le style mixedCase comme creatorAddress, supply.

  • Constantes

    - Utilisez toutes les lettres majuscules avec trait de soulignement pour séparer les mots tels que MAX_BLOCKS.

  • Noms des modificateurs

    - Utilisez le style mixCase comme onlyAfter.

  • Noms d'énumération

    - Utilisez le style CapWords comme TokenGroup.

Une fonction est un groupe de code réutilisable qui peut être appelé n'importe où dans votre programme. Cela élimine le besoin d'écrire le même code encore et encore. Il aide les programmeurs à écrire des codes modulaires. Les fonctions permettent à un programmeur de diviser un gros programme en un certain nombre de fonctions petites et gérables.

Comme tout autre langage de programmation avancé, Solidity prend également en charge toutes les fonctionnalités nécessaires pour écrire du code modulaire à l'aide de fonctions. Cette section explique comment écrire vos propres fonctions dans Solidity.

Définition de fonction

Avant d'utiliser une fonction, nous devons la définir. La manière la plus courante de définir une fonction dans Solidity est d'utiliser lefunction mot-clé, suivi d'un nom de fonction unique, d'une liste de paramètres (qui peuvent être vides) et d'un bloc d'instructions entouré d'accolades.

Syntaxe

La syntaxe de base est présentée ici.

function function-name(parameter-list) scope returns() {
   //statements
}

Exemple

Essayez l'exemple suivant. Il définit une fonction appelée getResult qui ne prend aucun paramètre -

pragma solidity ^0.5.0;

contract Test {
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

Appeler une fonction

Pour appeler une fonction quelque part plus tard dans le contrat, il vous suffit d'écrire le nom de cette fonction comme indiqué dans le code suivant.

Essayez le code suivant pour comprendre comment la chaîne fonctionne dans Solidity.

pragma solidity ^0.5.0;

contract SolidityTest {   
   constructor() public{       
   }
   function getResult() public view returns(string memory){
      uint a = 1; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }
   function integerToString(uint _i) internal pure 
      returns (string memory) {
      
      if (_i == 0) {
         return "0";
      }
      uint j = _i;
      uint len;
      
      while (j != 0) {
         len++;
         j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;
      
      while (_i != 0) {
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      return string(bstr);//access local variable
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: string: 3

Paramètres de fonction

Jusqu'à présent, nous avons vu des fonctions sans paramètres. Mais il existe une possibilité de passer différents paramètres lors de l'appel d'une fonction. Ces paramètres passés peuvent être capturés dans la fonction et toute manipulation peut être effectuée sur ces paramètres. Une fonction peut prendre plusieurs paramètres séparés par une virgule.

Exemple

Essayez l'exemple suivant. Nous avons utilisé unuint2strfonction ici. Cela prend un paramètre.

pragma solidity ^0.5.0;

contract SolidityTest {   
   constructor() public{       
   }
   function getResult() public view returns(string memory){
      uint a = 1; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }
   function integerToString(uint _i) internal pure 
      returns (string memory) {
      
      if (_i == 0) {
         return "0";
      }
      uint j = _i;
      uint len;
      
      while (j != 0) {
         len++;
         j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;
      
      while (_i != 0) {
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      return string(bstr);//access local variable
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: string: 3

La déclaration de retour

Une fonction Solidity peut avoir une option returndéclaration. Ceci est obligatoire si vous souhaitez renvoyer une valeur à partir d'une fonction. Cette instruction doit être la dernière instruction d'une fonction.

Comme dans l'exemple ci-dessus, nous utilisons la fonction uint2str pour renvoyer une chaîne.

Dans Solidity, une fonction peut également renvoyer plusieurs valeurs. Voir l'exemple ci-dessous -

pragma solidity ^0.5.0;

contract Test {
   function getResult() public view returns(uint product, uint sum){
      uint a = 1; // local variable
      uint b = 2;
      product = a * b;
      sum = a + b;
  
      //alternative return statement to return 
      //multiple values
      //return(a*b, a+b);
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: uint256: product 2
1: uint256: sum 3

Les modificateurs de fonction sont utilisés pour modifier le comportement d'une fonction. Par exemple, pour ajouter un prérequis à une fonction.

Nous créons d'abord un modificateur avec ou sans paramètre.

contract Owner {
   modifier onlyOwner {
      require(msg.sender == owner);
      _;
   }
   modifier costs(uint price) {
      if (msg.value >= price) {
         _;
      }
   }
}

Le corps de la fonction est inséré là où le symbole spécial "_;" apparaît dans la définition d'un modificateur. Donc, si la condition du modificateur est satisfaite lors de l'appel de cette fonction, la fonction est exécutée et sinon, une exception est levée.

Voir l'exemple ci-dessous -

pragma solidity ^0.5.0;

contract Owner {
   address owner;
   constructor() public {
      owner = msg.sender;
   }
   modifier onlyOwner {
      require(msg.sender == owner);
      _;
   }
   modifier costs(uint price) {
      if (msg.value >= price) {
         _;
      }
   }
}
contract Register is Owner {
   mapping (address => bool) registeredAddresses;
   uint price;
   constructor(uint initialPrice) public { price = initialPrice; }
   
   function register() public payable costs(price) {
      registeredAddresses[msg.sender] = true;
   }
   function changePrice(uint _price) public onlyOwner {
      price = _price;
   }
}

Les fonctions d'affichage garantissent qu'elles ne modifieront pas l'état. Une fonction peut être déclarée commeview. Les instructions suivantes, si présentes dans la fonction, sont considérées comme modifiant l'état et le compilateur lancera un avertissement dans de tels cas.

  • Modification des variables d'état.

  • Emission d'événements.

  • Création d'autres contrats.

  • Utilisation de l'autodestruction.

  • Envoi d'Ether via des appels.

  • Appel de toute fonction qui n'est pas marquée vue ou pure.

  • Utilisation d'appels de bas niveau.

  • Utilisation d'un assemblage en ligne contenant certains opcodes.

Les méthodes Getter sont par défaut des fonctions d'affichage.

Voir l'exemple ci-dessous en utilisant une fonction d'affichage.

Exemple

pragma solidity ^0.5.0;

contract Test {
   function getResult() public view returns(uint product, uint sum){
      uint a = 1; // local variable
      uint b = 2;
      product = a * b;
      sum = a + b; 
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: uint256: product 2
1: uint256: sum 3

Les fonctions pures garantissent qu'elles ne lisent ni ne modifient l'état. Une fonction peut être déclarée commepure. Les instructions suivantes, si présentes dans la fonction, sont considérées comme lisant l'état et le compilateur lancera un avertissement dans de tels cas.

  • Lecture des variables d'état.

  • Adresse d'accès (this) .balance ou <address> .balance.

  • Accéder à l'une des variables spéciales de block, tx, msg (msg.sig et msg.data peuvent être lus).

  • Appel de toute fonction non marquée pure.

  • Utilisation d'un assemblage en ligne contenant certains opcodes.

Les fonctions pures peuvent utiliser les fonctions revert () et require () pour annuler les changements d'état potentiels en cas d'erreur.

Voir l'exemple ci-dessous en utilisant une fonction d'affichage.

Exemple

pragma solidity ^0.5.0;

contract Test {
   function getResult() public pure returns(uint product, uint sum){
      uint a = 1; 
      uint b = 2;
      product = a * b;
      sum = a + b; 
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: uint256: product 2
1: uint256: sum 3

La fonction de secours est une fonction spéciale disponible pour un contrat. Il présente les caractéristiques suivantes -

  • Il est appelé lorsqu'une fonction inexistante est appelée sur le contrat.

  • Il doit être marqué externe.

  • Il n'a pas de nom.

  • Il n'a pas d'arguments

  • Il ne peut rien renvoyer.

  • Il peut être défini un par contrat.

  • S'il n'est pas marqué comme payable, il jettera une exception si le contrat reçoit de l'éther ordinaire sans données.

L'exemple suivant montre le concept d'une fonction de secours par contrat.

Exemple

pragma solidity ^0.5.0;

contract Test {
   uint public x ;
   function() external { x = 1; }    
}
contract Sink {
   function() external payable { }
}
contract Caller {
   function callTest(Test test) public returns (bool) {
      (bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()"));
      require(success);
      // test.x is now 1

      address payable testPayable = address(uint160(address(test)));

      // Sending ether to Test contract,
      // the transfer will fail, i.e. this returns false here.
      return (testPayable.send(2 ether));
   }
   function callSink(Sink sink) public returns (bool) {
      address payable sinkPayable = address(sink);
      return (sinkPayable.send(2 ether));
   }
}

Vous pouvez avoir plusieurs définitions pour le même nom de fonction dans la même étendue. La définition de la fonction doit différer les unes des autres par les types et / ou le nombre d'arguments dans la liste d'arguments. Vous ne pouvez pas surcharger les déclarations de fonction qui diffèrent uniquement par le type de retour.

L'exemple suivant montre le concept de surcharge de fonction dans Solidity.

Exemple

pragma solidity ^0.5.0;

contract Test {
   function getSum(uint a, uint b) public pure returns(uint){      
      return a + b;
   }
   function getSum(uint a, uint b, uint c) public pure returns(uint){      
      return a + b + c;
   }
   function callSumWithTwoArguments() public pure returns(uint){
      return getSum(1,2);
   }
   function callSumWithThreeArguments() public pure returns(uint){
      return getSum(1,2,3);
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Cliquez d'abord sur le bouton callSumWithTwoArguments, puis sur le bouton callSumWithThreeArguments pour voir le résultat.

Production

0: uint256: 3
0: uint256: 6

Solidity fournit également des fonctions mathématiques intégrées. Voici les méthodes très utilisées -

  • addmod(uint x, uint y, uint k) returns (uint)- calcule (x + y)% k où l'addition est effectuée avec une précision arbitraire et ne s'enroule pas à 2 256 .

  • mulmod(uint x, uint y, uint k) returns (uint)- calcule (x * y)% k où l'addition est effectuée avec une précision arbitraire et ne s'enroule pas à 2 256 .

L'exemple suivant montre l'utilisation des fonctions mathématiques dans Solidity.

Exemple

pragma solidity ^0.5.0;

contract Test {   
   function callAddMod() public pure returns(uint){
      return addmod(4, 5, 3);
   }
   function callMulMod() public pure returns(uint){
      return mulmod(4, 5, 3);
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Cliquez d'abord sur le bouton callAddMod, puis sur le bouton callMulMod pour voir le résultat.

Production

0: uint256: 0
0: uint256: 2

Solidity fournit également des fonctions cryptographiques intégrées. Voici des méthodes importantes -

  • keccak256(bytes memory) returns (bytes32) - calcule le hachage Keccak-256 de l'entrée.

  • sha256(bytes memory) returns (bytes32) - calcule le hachage SHA-256 de l'entrée.

  • ripemd160(bytes memory) returns (bytes20) - calculer le hachage RIPEMD-160 de l'entrée.

  • sha256(bytes memory) returns (bytes32) - calcule le hachage SHA-256 de l'entrée.

  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)- récupérer l'adresse associée à la clé publique à partir de la signature de la courbe elliptique ou renvoyer zéro en cas d'erreur. Les paramètres de fonction correspondent aux valeurs ECDSA de la signature: r - 32 premiers octets de signature; s: deuxième 32 octets de signature; v: dernier octet de signature. Cette méthode renvoie une adresse.

L'exemple suivant montre l'utilisation de la fonction cryptographique dans Solidity.

Exemple

pragma solidity ^0.5.0;

contract Test {   
   function callKeccak256() public pure returns(bytes32 result){
      return keccak256("ABC");
   }  
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: bytes32: result 0xe1629b9dda060bb30c7908346f6af189c16773fa148d3366701fbaa35d54f3c8

Le modèle de retrait garantit qu'aucun appel de transfert direct n'est effectué, ce qui constitue une menace pour la sécurité. Le contrat suivant montre l'utilisation non sécurisée de l'appel de transfert pour envoyer de l'éther.

pragma solidity ^0.5.0;

contract Test {
   address payable public richest;
   uint public mostSent;

   constructor() public payable {
      richest = msg.sender;
      mostSent = msg.value;
   }
   function becomeRichest() public payable returns (bool) {
      if (msg.value > mostSent) {
         // Insecure practice
         richest.transfer(msg.value);
         richest = msg.sender;
         mostSent = msg.value;
         return true;
      } else {
         return false;
      }
   }
}

Le contrat ci-dessus peut être rendu inutilisable en faisant en sorte que le plus riche soit un contrat de fonction de secours défaillante. Lorsque la fonction de secours échoue, la fonction devientRichest () échoue également et le contrat restera bloqué pour toujours. Pour atténuer ce problème, nous pouvons utiliser Withdrawal Pattern.

Dans le modèle de retrait, nous réinitialiserons le montant en attente avant chaque transfert. Cela garantira que seul le contrat de l'appelant échoue.

pragma solidity ^0.5.0;

contract Test {
   address public richest;
   uint public mostSent;

   mapping (address => uint) pendingWithdrawals;

   constructor() public payable {
      richest = msg.sender;
      mostSent = msg.value;
   }
   function becomeRichest() public payable returns (bool) {
      if (msg.value > mostSent) {
         pendingWithdrawals[richest] += msg.value;
         richest = msg.sender;
         mostSent = msg.value;
         return true;
      } else {
         return false;
      }
   }
   function withdraw() public {
      uint amount = pendingWithdrawals[msg.sender];
      pendingWithdrawals[msg.sender] = 0;
      msg.sender.transfer(amount);
   }
}

L'accès restreint à un contrat est une pratique courante. Par défaut, un état de contrat est en lecture seule sauf s'il est spécifié comme public.

Nous pouvons restreindre qui peut modifier l'état du contrat ou appeler les fonctions d'un contrat à l'aide de modificateurs. Nous allons créer et utiliser plusieurs modificateurs comme expliqué ci-dessous -

  • onlyBy - une fois utilisé sur une fonction, seul l'appelant mentionné peut appeler cette fonction.

  • onlyAfter - une fois utilisée sur une fonction, cette fonction peut être appelée après une certaine période.

  • costs - une fois utilisée sur une fonction, l'appelant ne peut appeler cette fonction que si une certaine valeur est fournie.

Exemple

pragma solidity ^0.5.0;

contract Test {
   address public owner = msg.sender;
   uint public creationTime = now;

   modifier onlyBy(address _account) {
      require(
         msg.sender == _account,
         "Sender not authorized."
      );
      _;
   }
   function changeOwner(address _newOwner) public onlyBy(owner) {
      owner = _newOwner;
   }
   modifier onlyAfter(uint _time) {
      require(
         now >= _time,
         "Function called too early."
      );
      _;
   }
   function disown() public onlyBy(owner) onlyAfter(creationTime + 6 weeks) {
      delete owner;
   }
   modifier costs(uint _amount) {
      require(
         msg.value >= _amount,
         "Not enough Ether provided."
      );
      _;
      if (msg.value > _amount)
         msg.sender.transfer(msg.value - _amount);
   }
   function forceOwnerChange(address _newOwner) public payable costs(200 ether) {
      owner = _newOwner;
      if (uint(owner) & 0 == 1) return;        
   }
}

Contract in Solidity est similaire à une classe en C ++. Un contrat a les propriétés suivantes.

  • Constructor - Une fonction spéciale déclarée avec le mot-clé constructeur qui sera exécutée une fois par contrat et est appelée lors de la création d'un contrat.

  • State Variables - Variables par contrat pour stocker l'état du contrat.

  • Functions - Fonctions par contrat qui peuvent modifier les variables d'état pour modifier l'état d'un contrat.

Quantificateurs de visibilité

Voici différents quantificateurs de visibilité pour les fonctions / variables d'état d'un contrat.

  • external- Les fonctions externes sont destinées à être appelées par d'autres contrats. Ils ne peuvent pas être utilisés pour les appels internes. Pour appeler une fonction externe dans le contrat, cet appel.function_name () est requis. Les variables d'état ne peuvent pas être marquées comme externes.

  • public- Les fonctions / variables publiques peuvent être utilisées à la fois en externe et en interne. Pour la variable d'état public, Solidity crée automatiquement une fonction getter.

  • internal - Les fonctions / variables internes ne peuvent être utilisées qu'en interne ou par des contrats dérivés.

  • private - Les fonctions / variables privées ne peuvent être utilisées qu'en interne et pas même par des contrats dérivés.

Exemple

pragma solidity ^0.5.0;

contract C {
   //private state variable
   uint private data;
   
   //public state variable
   uint public info;

   //constructor
   constructor() public {
      info = 10;
   }
   //private function
   function increment(uint a) private pure returns(uint) { return a + 1; }
   
   //public function
   function updateData(uint a) public { data = a; }
   function getData() public view returns(uint) { return data; }
   function compute(uint a, uint b) internal pure returns (uint) { return a + b; }
}
//External Contract
contract D {
   function readData() public returns(uint) {
      C c = new C();
      c.updateData(7);         
      return c.getData();
   }
}
//Derived Contract
contract E is C {
   uint private result;
   C private c;
   
   constructor() public {
      c = new C();
   }  
   function getComputedResult() public {      
      result = compute(3, 5); 
   }
   function getResult() public view returns(uint) { return result; }
   function getData() public view returns(uint) { return c.info(); }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First . Exécutez diverses méthodes de contrats. Pour E.getComputedResult () suivi de E.getResult () montre -

Production

0: uint256: 8

L'héritage est un moyen d'étendre la fonctionnalité d'un contrat. Solidity prend en charge l'héritage simple et multiple. Voici les principaux faits saillants.

  • Un contrat dérivé peut accéder à tous les membres non privés, y compris les méthodes internes et les variables d'état. Mais l'utilisation de cela n'est pas autorisée.

  • Le remplacement de fonction est autorisé à condition que la signature de la fonction reste la même. En cas de différence des paramètres de sortie, la compilation échouera.

  • Nous pouvons appeler la fonction d'un super contrat en utilisant le mot clé super ou en utilisant le nom du super contrat.

  • En cas d'héritage multiple, l'appel de fonction à l'aide de super donne la préférence à la plupart des contrats dérivés.

Exemple

pragma solidity ^0.5.0;

contract C {
   //private state variable
   uint private data;
   
   //public state variable
   uint public info;

   //constructor
   constructor() public {
      info = 10;
   }
   //private function
   function increment(uint a) private pure returns(uint) { return a + 1; }
   
   //public function
   function updateData(uint a) public { data = a; }
   function getData() public view returns(uint) { return data; }
   function compute(uint a, uint b) internal pure returns (uint) { return a + b; }
}
//Derived Contract
contract E is C {
   uint private result;
   C private c;
   constructor() public {
      c = new C();
   }  
   function getComputedResult() public {      
      result = compute(3, 5); 
   }
   function getResult() public view returns(uint) { return result; }
   function getData() public view returns(uint) { return c.info(); }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First . Exécutez diverses méthodes de contrats. Pour E.getComputedResult () suivi de E.getResult () montre -

Production

0: uint256: 8

Le constructeur est une fonction spéciale déclarée en utilisant constructormot-clé. C'est une fonction optionnelle et est utilisée pour initialiser les variables d'état d'un contrat. Voici les principales caractéristiques d'un constructeur.

  • Un contrat ne peut avoir qu'un seul constructeur.

  • Un code constructeur est exécuté une fois lorsqu'un contrat est créé et il est utilisé pour initialiser l'état du contrat.

  • Après l'exécution d'un code constructeur, le code final est déployé sur la blockchain. Ce code comprend des fonctions publiques et du code accessible via des fonctions publiques. Le code constructeur ou toute méthode interne utilisée uniquement par le constructeur ne sont pas inclus dans le code final.

  • Un constructeur peut être public ou interne.

  • Un constructeur interne marque le contrat comme abstrait.

  • Si aucun constructeur n'est défini, un constructeur par défaut est présent dans le contrat.

pragma solidity ^0.5.0;

contract Test {
   constructor() public {}
}
  • Dans le cas où le contrat de base a un constructeur avec des arguments, chaque contrat dérivé doit les transmettre.

  • Le constructeur de base peut être initialisé directement en utilisant la manière suivante -

pragma solidity ^0.5.0;

contract Base {
   uint data;
   constructor(uint _data) public {
      data = _data;   
   }
}
contract Derived is Base (5) {
   constructor() public {}
}
  • Le constructeur de base peut être initialisé indirectement en utilisant la manière suivante -

pragma solidity ^0.5.0;

contract Base {
   uint data;
   constructor(uint _data) public {
      data = _data;   
   }
}
contract Derived is Base {
   constructor(uint _info) Base(_info * _info) public {}
}
  • Les méthodes directes et indirectes d'initialisation du constructeur de contrat de base ne sont pas autorisées.

  • Si le contrat dérivé ne passe pas d'argument (s) au constructeur du contrat de base, le contrat dérivé deviendra abstrait.

Le contrat abstrait est celui qui contient au moins une fonction sans aucune implémentation. Un tel contrat est utilisé comme contrat de base. En général, un contrat abstrait contient à la fois des fonctions implémentées et des fonctions abstraites. Le contrat dérivé implémentera la fonction abstraite et utilisera les fonctions existantes au fur et à mesure des besoins.

Dans le cas où un contrat dérivé n'implémente pas la fonction abstraite, ce contrat dérivé sera marqué comme abstrait.

Exemple

Essayez le code suivant pour comprendre comment les contrats abstraits fonctionnent dans Solidity.

pragma solidity ^0.5.0;

contract Calculator {
   function getResult() public view returns(uint);
}
contract Test is Calculator {
   function getResult() public view returns(uint) {
      uint a = 1;
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Production

0: uint256: 3

Les interfaces sont similaires aux contrats abstraits et sont créées en utilisant interfacemot-clé. Voici les principales caractéristiques d'une interface.

  • L'interface ne peut avoir aucune fonction avec l'implémentation.

  • Les fonctions d'une interface ne peuvent être que de type externe.

  • L'interface ne peut pas avoir de constructeur.

  • L'interface ne peut pas avoir de variables d'état.

  • L'interface peut avoir des enum, des structures accessibles en utilisant la notation par points du nom de l'interface.

Exemple

Essayez le code suivant pour comprendre le fonctionnement de l'interface dans Solidity.

pragma solidity ^0.5.0;

interface Calculator {
   function getResult() external view returns(uint);
}
contract Test is Calculator {
   constructor() public {}
   function getResult() external view returns(uint){
      uint a = 1; 
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Note - Sélectionnez Test dans la liste déroulante avant de cliquer sur le bouton de déploiement.

Production

0: uint256: 3

Les bibliothèques sont similaires aux contrats mais sont principalement destinées à être réutilisées. Une bibliothèque contient des fonctions que d'autres contrats peuvent appeler. Solidity a certaines restrictions sur l'utilisation d'une bibliothèque. Voici les principales caractéristiques d'une Solidity Library.

  • Les fonctions de bibliothèque peuvent être appelées directement si elles ne modifient pas l'état. Cela signifie que les fonctions pures ou vues ne peuvent être appelées que depuis l'extérieur de la bibliothèque.

  • La bibliothèque ne peut pas être détruite car elle est supposée être apatride.

  • Une bibliothèque ne peut pas avoir de variables d'état.

  • Une bibliothèque ne peut hériter d'aucun élément.

  • Une bibliothèque ne peut pas être héritée.

Exemple

Essayez le code suivant pour comprendre le fonctionnement d'une bibliothèque dans Solidity.

pragma solidity ^0.5.0;

library Search {
   function indexOf(uint[] storage self, uint value) public view returns (uint) {
      for (uint i = 0; i < self.length; i++) if (self[i] == value) return i;
      return uint(-1);
   }
}
contract Test {
   uint[] data;
   constructor() public {
      data.push(1);
      data.push(2);
      data.push(3);
      data.push(4);
      data.push(5);
   }
   function isValuePresent() external view returns(uint){
      uint value = 4;
      
      //search if value is present in the array using Library function
      uint index = Search.indexOf(data, value);
      return index;
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Note - Sélectionnez Test dans la liste déroulante avant de cliquer sur le bouton de déploiement.

Production

0: uint256: 3

Utilisation pour

La directive using A for B; peuvent être utilisées pour attacher des fonctions de bibliothèque de la bibliothèque A à un type donné B. Ces fonctions utiliseront le type de l'appelant comme premier paramètre (identifié en utilisant self).

Exemple

Essayez le code suivant pour comprendre le fonctionnement d'une bibliothèque dans Solidity.

pragma solidity ^0.5.0;

library Search {
   function indexOf(uint[] storage self, uint value) public view returns (uint) {
      for (uint i = 0; i < self.length; i++)if (self[i] == value) return i;
      return uint(-1);
   }
}
contract Test {
   using Search for uint[];
   uint[] data;
   constructor() public {
      data.push(1);
      data.push(2);
      data.push(3);
      data.push(4);
      data.push(5);
   }
   function isValuePresent() external view returns(uint){
      uint value = 4;      
      
      //Now data is representing the Library
      uint index = data.indexOf(value);
      return index;
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Note - Sélectionnez Test dans la liste déroulante avant de cliquer sur le bouton de déploiement.

Production

0: uint256: 3

Solidity fournit une option permettant d'utiliser le langage d'assemblage pour écrire un assemblage en ligne dans le code source de Solidity. Nous pouvons également écrire un code d'assemblage autonome qui sera ensuite converti en bytecode. Standalone Assembly est un langage intermédiaire pour un compilateur Solidity et il convertit le code Solidity en un assemblage autonome, puis en code octet. Nous pouvons utiliser le même langage utilisé dans Inline Assembly pour écrire du code dans un assembly Standalone.

Assemblage en ligne

Le code d'assemblage en ligne peut être entrelacé dans la base de code Solidity pour avoir un contrôle plus fin sur EVM et est utilisé en particulier lors de l'écriture des fonctions de la bibliothèque.

Un code d'assemblage est écrit sous assembly { ... } bloquer.

Exemple

Essayez le code suivant pour comprendre le fonctionnement d'une bibliothèque dans Solidity.

pragma solidity ^0.5.0;

library Sum {   
   function sumUsingInlineAssembly(uint[] memory _data) public pure returns (uint o_sum) {
      for (uint i = 0; i < _data.length; ++i) {
         assembly {
            o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20))))
         }
      }
   }
}
contract Test {
   uint[] data;
   
   constructor() public {
      data.push(1);
      data.push(2);
      data.push(3);
      data.push(4);
      data.push(5);
   }
   function sum() external view returns(uint){      
      return Sum.sumUsingInlineAssembly(data);
   }
}

Exécutez le programme ci-dessus en suivant les étapes fournies dans le chapitre Application Solidity First .

Note - Sélectionnez Test dans la liste déroulante avant de cliquer sur le bouton de déploiement.

Production

0: uint256: 15

L'événement est un membre héréditaire d'un contrat. Un événement est émis, il stocke les arguments passés dans les journaux de transactions. Ces journaux sont stockés sur la blockchain et sont accessibles à l'aide de l'adresse du contrat jusqu'à ce que le contrat soit présent sur la blockchain. Un événement généré n'est pas accessible depuis l'intérieur des contrats, pas même celui qui les a créés et émis.

Un événement peut être déclaré à l'aide du mot-clé event.

//Declare an Event
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);

//Emit an event
emit Deposit(msg.sender, _id, msg.value);

Exemple

Essayez le code suivant pour comprendre le fonctionnement d'un événement dans Solidity.

Créez d'abord un contrat et émettez un événement.

pragma solidity ^0.5.0;

contract Test {
   event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
   function deposit(bytes32 _id) public payable {      
      emit Deposit(msg.sender, _id, msg.value);
   }
}

Accédez ensuite à l'événement du contrat en code JavaScript.

var abi = /* abi as generated using compiler */;
var ClientReceipt = web3.eth.contract(abi);
var clientReceiptContract = ClientReceipt.at("0x1234...ab67" /* address */);

var event = clientReceiptContract.Deposit(function(error, result) {
   if (!error)console.log(result);
});

Il doit imprimer des détails similaires à ce qui suit -

Production

{
   "returnValues": {
      "_from": "0x1111...FFFFCCCC",
      "_id": "0x50...sd5adb20",
      "_value": "0x420042"
   },
   "raw": {
      "data": "0x7f...91385",
      "topics": ["0xfd4...b4ead7", "0x7f...1a91385"]
   }
}

Solidity propose diverses fonctions de gestion des erreurs. En général, lorsqu'une erreur se produit, l'état revient à son état d'origine. D'autres contrôles visent à empêcher l'accès non autorisé au code. Voici quelques-unes des méthodes importantes utilisées dans la gestion des erreurs -

  • assert(bool condition)- Si la condition n'est pas remplie, cet appel de méthode provoque un opcode invalide et toutes les modifications apportées à l'état sont annulées. Cette méthode doit être utilisée pour les erreurs internes.

  • require(bool condition)- Si la condition n'est pas remplie, cet appel de méthode revient à l'état d'origine. - Cette méthode doit être utilisée pour les erreurs d'entrées ou de composants externes.

  • require(bool condition, string memory message)- Si la condition n'est pas remplie, cet appel de méthode revient à l'état d'origine. - Cette méthode doit être utilisée pour les erreurs d'entrées ou de composants externes. Il fournit une option pour fournir un message personnalisé.

  • revert() - Cette méthode annule l'exécution et annule toutes les modifications apportées à l'état.

  • revert(string memory reason)- Cette méthode annule l'exécution et annule toutes les modifications apportées à l'état. Il fournit une option pour fournir un message personnalisé.

Exemple

Essayez le code suivant pour comprendre le fonctionnement de la gestion des erreurs dans Solidity.

pragma solidity ^0.5.0;

contract Vendor {
   address public seller;
   modifier onlySeller() {
      require(
         msg.sender == seller,
         "Only seller can call this."
      );
      _;
   }
   function sell(uint amount) public payable onlySeller { 
      if (amount > msg.value / 2 ether)
         revert("Not enough Ether provided.");
      // Perform the sell operation.
   }
}

Lorsque revert est appelé, il renverra les données hexadécimales comme suit.

Production

0x08c379a0                     // Function selector for Error(string)
0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset
0x000000000000000000000000000000000000000000000000000000000000001a // String length
0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data