Appendix A: Outils, cadres, et bibliothèques de développement

Bannière Amazon du livre Maîtriser Ethereum

Cadres de développement (Frameworks)

Les cadres de développement peuvent être utilisés pour faciliter le développement de contrats intelligents Ethereum. En faisant tout vous-même, vous comprenez mieux comment tout s’emboîte, mais c’est beaucoup de travail fastidieux et répétitif. Les cadres de développement décrits dans cette section permettent d’automatiser certaines tâches et de faciliter la programmation.

Truffle

Référentiel de packages npm : https://www.npmjs.com/package/truffle

Installation du cadre de développement Truffle

Le cadre de développement Truffle comprend plusieurs packages Node.js. Avant d’installer truffle, vous devez avoir une installation à jour et fonctionnelle de Node.js et du Node Package Manager (npm).

La méthode recommandée pour installer Node.js et npm consiste à utiliser le gestionnaire de version de nœud (nvm). Une fois que vous avez installé nvm, il gérera toutes les dépendances et mises à jour pour vous. Suivez les instructions trouvées sur http://nvm.sh.

Une fois que nvm est installé sur votre système d’exploitation, l’installation de Node.js est simple. Utilisez le drapeau --lts pour dire à nvm que vous voulez la version la plus récente de "support à long terme" (LTS) de Node.js :

$ nvm install --lts

Vérifiez que node et npm sont installés :

$ node -v
v8.9.4
$ npm -v
5.6.0

Ensuite, créez un fichier caché, .nvmrc, qui contient la version Node.js prise en charge par votre DApp afin que les développeurs n’aient qu’à exécuter "nvm install" à la racine du répertoire du projet et il s’installera automatiquement et passera à l’utilisation de cette version. :

$ node -v > .nvmrc
$ nvm install

Ça parait bien. Maintenant, installons truffle :

$ npm -g install truffle

+ [email protected]
installed 1 package in 37.508s

Intégration d’un projet Truffle préconstruit (Truffle Box)

Si vous souhaitez utiliser ou créer une DApp qui s’appuie sur un passe-partout prédéfini, accédez au site Web de Truffle Boxes, choisissez un projet Truffle existant, puis exécutez la commande suivante pour le télécharger et l’extraire :

$ truffle unbox BOX_NAME

Création d’un répertoire de projet truffle

Pour chaque projet où vous utiliserez truffle, créez un répertoire de projet et initialisez truffle dans ce répertoire. truffle créera la structure de répertoire nécessaire dans le répertoire de votre projet. Il est d’usage de donner au répertoire du projet un nom qui décrit le projet. Pour cet exemple, nous utiliserons truffle pour déployer notre contrat Faucet depuis [simple_contract_example], et donc nous nommerons le dossier du projet Faucet :

$ mkdir Faucet
$ cd Faucet
Faucet $

Une fois dans le répertoire Faucet, nous initialisons truffle :

Faucet $ truffle init

truffle crée une structure de répertoires et des fichiers par défaut :

Faucet
+---- contracts
|   `---- Migrations.sol
+---- migrations
|   `---- 1_initial_migration.js
+---- test
+---- truffle-config.js
`---- truffle.js

Nous utiliserons également un certain nombre de packages de support JavaScript (Node.js), en plus de truffle lui-même. Nous pouvons les installer avec npm. Nous initialisons la structure de répertoires npm et acceptons les valeurs par défaut suggérées par npm :

$ npm init

package name: (faucet)
version: (1.0.0)
description:
entry point: (truffle-config.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to Faucet/package.json:

{
  "name": "faucet",
  "version": "1.0.0",
  "description": "",
  "main": "truffle-config.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes)

Maintenant, nous pouvons installer les dépendances que nous utiliserons pour faciliter le travail avec truffle :

$ npm install dotenv truffle-wallet-provider ethereumjs-wallet

Nous avons maintenant un répertoire node_modules avec plusieurs milliers de fichiers dans notre répertoire Faucet.

Avant de déployer un DApp dans un environnement de production cloud ou d’intégration continue, il est important de spécifier le champ engines afin que votre DApp soit construit avec la bonne version de Node.js et que ses dépendances associées soient installées. Pour plus de détails sur la configuration de ce champ, consultez la documentation.

Configuration de truffle

truffle crée des fichiers de configuration vides, truffle.js et truffle-config.js. Sur les systèmes Windows, le nom truffle.js peut provoquer un conflit lorsque vous essayez d’exécuter la commande truffle et que Windows tente d’exécuter truffle.js à la place. Pour éviter cela, nous allons supprimer truffle.js et utiliser truffle-config.js (en soutien aux utilisateurs de Windows, qui, honnêtement, souffrent déjà assez) :

$ rm truffle.js

Maintenant, nous éditons truffle-config.js et remplaçons le contenu par l’exemple de configuration montré ici :

module.exports = {
  networks: {
    localnode: { // Quel que soit le réseau auquel notre nœud local se connecte
      network_id: "*", // Correspond à n'importe quel ID de réseau
      host: "localhost",
      port: 8545,
    }
  }
};

Cette configuration est un bon point de départ. Il configure un réseau Ethereum par défaut (nommé localnode), qui suppose que nous exécutons un client Ethereum tel que Parity, soit en tant que nœud complet, soit en tant que client léger. Cette configuration demandera à truffle de communiquer avec le nœud local via RPC, sur le port 8545. truffle utilisera le réseau Ethereum auquel le nœud local est connecté, comme le réseau principal Ethereum ou un réseau de test comme Ropsten. Le nœud local fournira également la fonctionnalité de portefeuille.

Dans les sections suivantes, nous configurerons des réseaux supplémentaires pour truffle à utiliser, tels que la chaîne de blocs de test locale ganache et Infura, un fournisseur de réseau hébergé. Au fur et à mesure que nous ajouterons des réseaux, le fichier de configuration deviendra plus complexe, mais il nous donnera également plus d’options pour notre flux de travail de test et de développement.

Utiliser truffle pour déployer un contrat

Nous avons maintenant un répertoire de travail de base pour notre projet Faucet, et nous avons truffle et ses dépendances configurées. Les contrats vont dans le sous-répertoire contracts de notre projet. Le répertoire contient déjà un contrat "d’aide", Migrations.sol, qui gère pour nous les mises à jour des contrats. Nous examinerons l’utilisation de Migrations.sol dans la section suivante.

Copions le contrat Faucet.sol (depuis [solidity_faucet_example]) dans le sous-répertoire contracts, de sorte que le répertoire du projet ressemble à ceci :

Faucet
+---- contracts
|   +---- Faucet.sol
|   `---- Migrations.sol
...

Nous pouvons maintenant demander à truffle de compiler le contrat pour nous :

$ truffle compile
Compiling ./contracts/Faucet.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts

Migrations Truffle—comprendre les scripts de déploiement

Truffle propose un système de déploiement appelé migration. Si vous avez travaillé dans d’autres cadres de développement, vous avez peut-être vu quelque chose de similaire : Ruby on Rails, Python Django et de nombreux autres langages et cadres de développement ont une commande migrate.

Dans tous ces cadres de développement, le but d’une migration est de gérer les modifications du schéma de données entre différentes versions du logiciel. Le but des migrations dans Ethereum est légèrement différent. Parce que les contrats Ethereum sont immuables et coûtent du gaz à déployer, Truffle propose un mécanisme de migration pour garder une trace des contrats (et des versions) qui ont déjà été déployés. Dans un projet complexe avec des dizaines de contrats et des dépendances complexes, vous ne voudriez pas avoir à payer pour redéployer des contrats qui n’ont pas changé. Vous ne voudriez pas non plus suivre manuellement quelles versions de quels contrats ont déjà été déployées. Le mécanisme de migration Truffle fait tout cela en déployant le contrat intelligent Migrations.sol, qui suit ensuite tous les autres déploiements de contrat.

Nous n’avons qu’un seul contrat, Faucet.sol, ce qui signifie que le système de migration est pour le moins exagéré. Malheureusement, nous devons l’utiliser. Mais, en apprenant à l’utiliser pour un contrat, nous pouvons commencer à mettre en pratique de bonnes habitudes pour notre flux de travail de développement. L’effort sera payant au fur et à mesure que les choses se compliqueront.

Le répertoire migrations de Truffle est l’endroit où se trouvent les scripts de migration. À l’heure actuelle, il n’y a qu’un seul script, 1_initial_migration.js, qui déploie le contrat Migrations.sol lui-même :

var Migrations = artifacts.require("./Migrations.sol");

module.exports = function(deployer) {
  deployer.deploy(Migrations);
};

Nous avons besoin d’un deuxième script de migration, pour déployer Faucet.sol. Appelons-le 2_deploy_contracts.js. C’est très simple, tout comme 1_initial_migration.js, avec seulement quelques petites modifications. En fait, vous pouvez copier le contenu de 1_initial_migration.j et simplement remplacer toutes les instances de Migrations par Faucet :

var Faucet = artifacts.require("./Faucet.sol");

module.exports = function(deployer) {
  deployer.deploy(Faucet);
};

Le script initialise une variable Faucet, identifiant le code source Solidity Faucet.sol comme l’artefact qui définit Faucet. Ensuite, il appelle la fonction "deploy" pour déployer ce contrat.

Nous sommes prêts. Utilisons truffle migrate pour le déployer. Nous devons spécifier sur quel réseau déployer le contrat, en utilisant l’argument --network . Nous n’avons qu’un seul réseau spécifié dans le fichier de configuration, que nous avons nommé localnode. Assurez-vous que votre client Ethereum local est en cours d’exécution, puis tapez :

Faucet $ truffle migrate --network localnode

Comme nous utilisons un nœud local pour nous connecter au réseau Ethereum et gérer notre portefeuille, nous devons autoriser la transaction créée par truffle. Nous exécutons parity connecté à la chaîne de blocs de test de Ropsten, donc pendant la migration, nous verrons une fenêtre contextuelle comme celle de Parity demandant confirmation pour déployer Faucet sur la console web de Parity.

Parité demandant confirmation pour déployer Faucet
Figure 1. Parity demandant confirmation pour déployer Faucet

Il y a quatre transactions au total : une pour déployer Migrations, une pour mettre à jour le compteur de déploiements à 1, une pour déployer Faucet et une pour mettre à jour le compteur de déploiements à 2.

Truffle affichera les migrations terminées, affichera chacune des transactions et affichera les adresses de contrat :

$ truffle migrate --network localnode
Using network 'localnode'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xfa090db179d023d2abae543b4a21a1479e70ca7d35a469a5d1a98bfc6bd80fe8
  Migrations: 0x8861c27715550bed8362c0345add158489df6db0
Saving successful migration to network...
  ... 0x985c4a32716826ddbe4eae284104bef8bc69e959899f62246a1b27c9dfcd6c03
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying Faucet...
  ... 0xecdbeef77f0558edc689440e34b7bba0a3ba7a45e4b680b071b47c30a930e9d6
  Faucet: 0xd01cd8e7bd29e4bff8c1693f59eee46137a9f300
Saving successful migration to network...
  ... 0x11f376bd7307edddfd40dc4a14c3f7cb84b6c921ac2465602060b67d08f9fd8a
Saving artifacts...

Utilisation de la console Truffle

Truffle propose une console JavaScript que nous pouvons utiliser pour interagir avec le réseau Ethereum (via le noeud local), interagir avec les contrats déployés et interagir avec le fournisseur de portefeuille. Dans notre configuration actuelle (localnode), le fournisseur de nœud et de portefeuille est notre client Parity local.

Démarrons la console Truffle et essayons quelques commandes :

$ truffle console --network localnode
truffle(localnode)>

Truffle présente une invite indiquant la configuration réseau sélectionnée (localnode).

Tip

Il est important de se rappeler et de savoir quel réseau vous utilisez. Vous ne voudriez pas déployer accidentellement un contrat de test ou effectuer une transaction sur le réseau principal Ethereum. Cela pourrait être une erreur coûteuse!

La console Truffle offre une fonction de saisie semi-automatique qui nous permet d’explorer facilement l’environnement. Si nous appuyons sur Tab après une commande partiellement terminée, Truffle terminera la commande pour nous. Appuyer deux fois sur Tab affichera toutes les complétions possibles si plus d’une commande correspond à notre entrée. En fait, si nous appuyons deux fois sur Tab sur une invite vide, Truffle liste toutes les commandes disponibles :

truffle(localnode)>
Array Boolean Date Error EvalError Function Infinity JSON Math NaN Number Object RangeError ReferenceError RegExp String SyntaxError TypeError URIError decodeURI decodeURIComponent encodeURI encodeURIComponent eval isFinite isNaN parseFloat parseInt undefined

ArrayBuffer Buffer DataView Faucet Float32Array Float64Array GLOBAL Int16Array Int32Array Int8Array Intl Map Migrations Promise Proxy Reflect Set StateManager Symbol Uint16Array Uint32Array Uint8Array Uint8ClampedArray WeakMap WeakSet WebAssembly XMLHttpRequest _ assert async_hooks buffer child_process clearImmediate clearInterval clearTimeout cluster console crypto dgram dns domain escape events fs global http http2 https module net os path perf_hooks process punycode querystring readline repl require root setImmediate setInterval setTimeout stream string_decoder tls tty unescape url util v8 vm web3 zlib

__defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__ __proto__ constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf

La grande majorité des fonctions liées au portefeuille et aux nœuds sont fournies par l’objet web3, qui est une instance de la bibliothèque web3.js. L’objet web3 résume l’interface RPC à notre nœud Parity. Vous remarquerez également deux objets aux noms familiers : Migrations et Faucet. Ceux-ci représentent les contrats que nous venons de déployer. Nous utiliserons la console Truffle pour interagir avec un contrat. Tout d’abord, vérifions notre wallet via l’objet web3 :

truffle(localnode)> web3.eth.accounts
[ '0x9e713963a92c02317a681b9bb3065a8249de124f',
  '0xdb5dc1a13e3a55cf3b4587cd8d1e5fdeb6738145' ]

Notre client Parity a deux portefeuilles, avec un peu d’ether de test sur Ropsten. L’attribut web3.eth.accounts contient une liste de tous les comptes. Nous pouvons vérifier le solde du premier compte en utilisant la fonction getBalance :

truffle(localnode)> web3.eth.getBalance(web3.eth.accounts[0]).toNumber()
191198572800000000
truffle(localnode)>

web3.js est une grande bibliothèque JavaScript qui offre une interface complète au système Ethereum, via un fournisseur tel qu’un client local. Nous examinerons web3.js plus en détail dans [web3js_tutorial]. Essayons maintenant d’interagir avec nos contrats :

truffle(localnode)> Faucet.address
'0xd01cd8e7bd29e4bff8c1693f59eee46137a9f300'
truffle(localnode)> web3.eth.getBalance(Faucet.address).toNumber()
0
truffle(localnode)>

Ensuite, nous utiliserons sendTransaction pour envoyer de l’ether de test afin de financer le contrat Faucet. Notez l’utilisation de web3.utils.toWei pour convertir les unités ether pour nous. Taper 18 zéros sans se tromper est à la fois difficile et dangereux, il est donc toujours préférable d’utiliser un convertisseur d’unités pour les valeurs. Voici comment nous envoyons la transaction :

truffle(localnode)> web3.eth.sendTransaction({from:web3.eth.accounts[0],
                    to:Faucet.address, value:web3.utils.toWei(0.5, 'ether')});
'0xf134c75b985dc0e0c27c2f0412251e0860eb530a5055e660f21e7483ab336808'

Si nous passons à l’interface Web de Parity, nous verrons une fenêtre contextuelle nous demandant de confirmer cette transaction. Une fois la transaction extraite, nous pourrons voir le solde de notre contrat Faucet :

truffle(localnode)> web3.eth.getBalance(Faucet.address).toNumber()
500000000000000000

Appelons maintenant la fonction withdraw, pour retirer de l’ether de test du contrat :

truffle(localnode)> Faucet.deployed().then(instance =>
                       {instance.withdraw(web3.utils.toWei(0.1,
                       'ether'))}).then(console.log)

Encore une fois, nous devrons approuver la transaction dans l’interface Web de Parity. Si nous vérifions à nouveau, nous verrons que le solde du contrat Faucet a diminué et que notre portefeuille de test a reçu 0,1 ether:

truffle(localnode)> web3.eth.getBalance(Faucet.address).toNumber()
400000000000000000
truffle(localnode)> Faucet.deployed().then(instance =>
                    {instance.withdraw(web3.utils.toWei(1, 'ether'))})
StatusError: Transaction: 0xe147ae9e3610334...8612b92d3f9c
  exited with an error (status 0).

Embark

Référentiel de packages npm : https://www.npmjs.com/package/embark

Embark est un framework conçu pour permettre aux développeurs de développer et de déployer facilement des applications décentralisées. Embark s’intègre à Ethereum, IPFS, Whisper et Swarm pour offrir les fonctionnalités suivantes :

  • Déployer automatiquement les contrats et les rendre disponibles en code JS.

  • Surveiller les changements et mettez à jour les contrats pour les redéployer si nécessaire.

  • Gérer et interagir avec différentes chaînes (par exemple, testnet, local, mainnet).

  • Gérer des systèmes complexes de contrats interdépendants.

  • Stocker et récupérer des données, y compris le téléchargement et la récupération de fichiers hébergés dans IPFS.

  • Faciliter le processus de déploiement de l’application complète sur IPFS ou Swarm.

  • Envoyer et recevoir des messages via Whisper.

Vous pouvez l’installer avec npm :

$ npm -g install embark

OpenZeppelin

OpenZeppelin est un cadre ouvert de contrats intelligents réutilisables et sécurisés dans le langage Solidity.

Il est piloté par la communauté, dirigé par l’équipe Zeppelin, avec plus d’une centaine de contributeurs externes. L’objectif principal du cadre est la sécurité, obtenue en appliquant des modèles de sécurité de contrat standard et les meilleures pratiques, en s’appuyant sur toute l’expérience que les développeurs Zeppelin ont acquise en auditant un grand nombre de contrats, et grâce à des tests et des audits constants de la part de la communauté qui utilise le cadre de développement comme base pour leurs applications dans le monde réel.

Le cadre de développement OpenZeppelin est la solution la plus largement utilisée pour les contrats intelligents Ethereum. Le cadre de développement dispose actuellement d’une vaste bibliothèque de contrats, y compris des implémentations de jetons ERC20 et ERC721, de nombreuses variantes de modèles de vente publique et des comportements simples que l’on trouve couramment dans des contrats tels que "Ownable", "Pausable" ou "LimitBalance". Les contrats de ce référentiel fonctionnent dans certains cas comme des implémentations standard de facto.

Le cadre est sous licence MIT, et tous les contrats ont été conçus avec une approche modulaire pour garantir la facilité de réutilisation et d’extension. Ce sont des blocs de construction propres et basiques, prêts à être utilisés dans votre prochain projet Ethereum. Configurons le cadre et construisons une simple vente publique à l’aide des contrats OpenZeppelin, pour démontrer à quel point il est facile à utiliser. Cet exemple souligne également l’importance de réutiliser des composants sécurisés au lieu de les écrire par vous-même.

Tout d’abord, nous devrons installer la bibliothèque openzeppelin-solidity dans notre espace de travail. La dernière version au moment d’écrire ces lignes est la v1.9.0, nous allons donc l’utiliser :

$ mkdir sample-crowdsale
$ cd sample-crowdsale
$ npm install [email protected]
$ mkdir contracts

Au moment de la rédaction, OpenZeppelin comprend plusieurs contrats de jetons de base qui suivent les normes ERC20, ERC721 et ERC827, avec différentes caractéristiques d’émission, de limites, d’acquisition, de cycle de vie, etc.

Créons un jeton ERC20 monnayable, ce qui signifie que l’approvisionnement initial commence à 0 et que de nouveaux jetons peuvent être créés par le propriétaire du jeton (dans notre cas, le contrat de vente publique) et vendus aux acheteurs. Pour ce faire, nous allons créer un fichier contracts/SampleToken.sol avec le contenu suivant :

pragma solidity 0.4.23;

import 'openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol';

contract SampleToken is MintableToken {
  string public name = "SAMPLE TOKEN";
  string public symbol = "SAM";
  uint8 public decimals = 18;
}

OpenZeppelin fournit déjà un contrat MintableToken que nous pouvons utiliser comme base pour notre jeton, nous ne définissons donc que les détails spécifiques à notre cas. Ensuite, faisons le contrat de vente publique. Tout comme avec les jetons, OpenZeppelin propose déjà une grande variété de saveurs de vente publique. Actuellement, vous trouverez des contrats pour divers scénarios impliquant la distribution, l’émission, le prix et la validation. Donc, disons que vous voulez fixer un objectif pour votre vente publique et s’il n’est pas atteint au moment où la vente se termine, vous voulez rembourser tous vos investisseurs. Pour cela, vous pouvez utiliser le contrat RefundableCrowdsale. Ou peut-être souhaitez-vous définir une vente publique avec un prix croissant pour inciter les premiers acheteurs ; il y a un contrat IncreasingPriceCrowdsalejuste pour ça. Vous pouvez également mettre fin à la vente publique lorsqu’une quantité spécifiée d’ether a été reçue par le contrat (CappedCrowdsale), ou définir une heure de fin avec le contrat TimedCrowdsale, ou créez une liste blanche d’acheteurs avec le contrat WhitelistedCrowdsale.

Comme nous l’avons dit précédemment, les contrats OpenZeppelin sont des éléments de base. Ces contrats de crowdsale ont été conçus pour être combinés ; il suffit de lire le code source du contrat de base Crowdsalepour savoir comment l’étendre. Pour la vente publique de notre jeton, nous devons créer des jetons lorsque l’ether est reçu par le contrat de vente publique, utilisons donc MintedCrowdsalecomme base. Et pour le rendre plus intéressant, faisons-en également une PostDeliveryCrowdsaleafin que les jetons ne puissent être retirés qu’après la fin de la vente publique. Pour ce faire, nous allons écrire ce qui suit dans contracts/SampleCrowdsale.sol :

pragma solidity 0.4.23;

import './SampleToken.sol';
import 'openzeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol';
import 'openzeppelin-solidity/contracts/crowdsale/ \
  distribution/PostDeliveryCrowdsale.sol';

contract SampleCrowdsale is PostDeliveryCrowdsale, MintedCrowdsale {

  constructor(
    uint256 _openingTime,
    uint256 _closingTime
    uint256 _rate,
    address _wallet,
    MintableToken _token
  )
    public
    Crowdsale(_rate, _wallet, _token)
    PostDeliveryCrowdsale(_openingTime, _closingTime)
  {
  }
}

Encore une fois, nous avons à peine eu à écrire du code ; nous venons de réutiliser le code testé au combat que la communauté OpenZeppelin a mis à disposition. Cependant, il est important de noter que ce cas est différent de celui de notre contrat SampleToken. Si vous allez sur les Tests automatisés Crowdsale, vous verrez qu’ils sont testés de manière isolée. Lorsque vous intégrez différentes unités de code dans un composant plus gros, il ne suffit pas de tester toutes les unités séparément, car les interactions entre elles peuvent provoquer des comportements auxquels vous ne vous attendiez pas. En particulier, vous verrez qu’ici nous avons introduit l’héritage multiple, ce qui peut surprendre le développeur s’il ne comprend pas les détails de Solidity. Notre SampleCrowdsale est simple et fonctionnera exactement comme prévu, car le cadre a été conçu pour simplifier des cas comme ceux-ci ; mais ne relâchez pas votre vigilance à cause de la simplicité qu’introduit ce cadre de développement. Chaque fois que vous intégrez des parties du cadre de développement OpenZeppelin pour créer une solution plus complexe, vous devez tester entièrement chaque aspect de votre solution pour vous assurer que toutes les interactions des unités fonctionnent comme vous le souhaitez.

Enfin, lorsque nous sommes satisfaits de notre solution et que nous l’avons testée de manière approfondie, nous devons la déployer. OpenZeppelin s’intègre bien à Truffle, nous pouvons donc simplement écrire un fichier de migration comme celui-ci (migrations/2_deploy_contracts.js), comme expliqué dans Migrations Truffle—comprendre les scripts de déploiement :

const SampleCrowdsale = artifacts.require('./SampleCrowdsale.sol');
const SampleToken = artifacts.require('./SampleToken.sol');

module.exports = function(deployer, network, accounts) {
  const openingTime = web3.eth.getBlock('latest').timestamp + 2; // 2s dans le futur
  const closingTime = openingTime + 86400 * 20; // 20 days
  const rate = new web3.BigNumber(1000);
  const wallet = accounts[1];

  return deployer
    .then(() => {
      return deployer.deploy(SampleToken);
    })
    .then(() => {
      return deployer.deploy(
        SampleCrowdsale,
        openingTime,
        closingTime,
        rate,
        wallet,
        SampleToken.address
      );
    });
};
Note

Ce n’était qu’un aperçu rapide de quelques-uns des contrats qui font partie du cadre OpenZeppelin. Vous êtes invités à rejoindre la communauté de développement OpenZeppelin pour apprendre et contribuer.

ZeppelinOS

ZeppelinOS est "une plate-forme open source distribuée d’outils et de services au-dessus de l’EVM pour développer et gérer en toute sécurité des applications de contrats intelligents.

Contrairement au code d’OpenZeppelin, qui doit être redéployé avec chaque application à chaque utilisation, le code de ZeppelinOS vit en chaîne. Les applications qui ont besoin d’une fonctionnalité donnée, par exemple un jeton ERC20, non seulement n’ont pas à reconcevoir et à réauditer sa mise en œuvre (quelque chose qu’OpenZeppelin a résolu), mais n’ont même pas besoin de la déployer. Avec ZeppelinOS, une application interagit directement avec l’implémentation en chaîne du jeton, de la même manière qu’une application de bureau interagit avec les composants de son système d’exploitation sous-jacent.

Au cœur de ZeppelinOS se trouve un contrat très intelligent connu sous le nom de proxy. Un proxy est un contrat capable d’encapsuler n’importe quel autre contrat, d’exposer son interface sans avoir à implémenter manuellement des setters et des getters pour celui-ci, et de le mettre à niveau sans perdre son état. En termes de solidité, il peut être considéré comme un contrat normal dont la logique métier est contenue dans une bibliothèque, qui peut être échangée contre une nouvelle bibliothèque à tout moment sans perdre son état. La manière dont le proxy est lié à son implémentation est entièrement automatisée et encapsulée pour le développeur. Pratiquement n’importe quel contrat peut être mis à niveau avec peu ou pas de changement dans son code. Plus d’informations sur le mécanisme de proxy de ZeppelinOS peuvent être trouvées dans le blog, et un exemple de la façon de l’utiliser peut être trouvé sur GitHub.

Le développement d’applications à l’aide de ZeppelinOS est similaire au développement d’applications JavaScript à l’aide de npm. Un AppManager gère un package d’application pour chaque version de l’application. Un package est simplement un répertoire de contrats, chacun pouvant avoir un ou plusieurs proxys pouvant être mis à niveau. Le AppManager fournit non seulement des proxys pour les contrats spécifiques à l’application, mais le fait également pour les implémentations de ZeppelinOS, sous la forme d’une bibliothèque standard. Pour en voir un exemple complet, veuillez visiter examples/complex.

Bien qu’actuellement en développement, ZeppelinOS vise à fournir un large éventail de fonctionnalités supplémentaires, telles que des outils de développement, un planificateur qui automatise les opérations en arrière-plan dans les contrats, des primes de développement, un marché qui facilite la communication et l’échange de valeur entre les applications, et bien plus encore. Tout cela est décrit dans le whitepaper. de ZeppelinOS

Utilitaires

EthereumJS aide : un utilitaire de ligne de commande

helpeth est un outil en ligne de commande pour la manipulation de clés et de transactions qui facilite grandement le travail d’un développeur.

Il fait partie de la collection EthereumJS de bibliothèques et d’outils basés sur JavaScript :

Usage: helpeth [command]

Commands:
  signMessage <message>                     Sign a message
  verifySig <hash> <sig>                    Verify signature
  verifySigParams <hash> <r> <s> <v>        Verify signature parameters
  createTx <nonce> <to> <value> <data>      Sign a transaction
  <gasLimit> <gasPrice>
  assembleTx <nonce> <to> <value> <data>    Assemble a transaction from its
  <gasLimit> <gasPrice> <v> <r> <s>         components
  parseTx <tx>                              Parse raw transaction
  keyGenerate [format] [icapdirect]         Generate new key
  keyConvert                                Convert a key to V3 keystore format
  keyDetails                                Print key details
  bip32Details <path>                       Print key details for a given path
  addressDetails <address>                  Print details about an address
  unitConvert <value> <from> <to>           Convert between Ethereum units

Options:
  -p, --private      Private key as a hex string                        [string]
  --password         Password for the private key                       [string]
  --password-prompt  Prompt for the private key password               [boolean]
  -k, --keyfile      Encoded key file                                   [string]
  --show-private     Show private key details                          [boolean]
  --mnemonic         Mnemonic for HD key derivation                     [string]
  --version          Show version number                               [boolean]
  --help             Show help                                         [boolean]

dapp.tools

Site Web : https://dapp.tools/

dapp.tools est une suite complète d’outils de développement orientés chaîne de blocs créés dans l’esprit de la philosophie Unix. Les outils inclus sont :

Dapp

Dapp est l’outil de base destiné à l’utilisateur, permettant de créer de nouveaux DApp, d’exécuter des tests unitaires Solidity, de déboguer et de déployer des contrats, de lancer des réseaux de test, etc.

Seth

Seth est utilisé pour composer des transactions, interroger la chaîne de blocs, convertir entre les formats de données, effectuer des appels à distance et des tâches quotidiennes similaires.

Hevm

Hevm est une implémentation Haskell EVM avec un débogueur Solidity agile basé sur un terminal. Il est utilisé pour tester et déboguer les DApps.

evmdis

evmdis est un désassembleur EVM ; il effectue une analyse statique sur le code intermédiaire pour fournir un niveau d’abstraction plus élevé que les opérations EVM brutes.

SputnikVM

SputnikVM est une machine virtuelle enfichable autonome pour différentes chaînes de blocs basées sur Ethereum. Il est écrit en Rust et peut être utilisé comme binaire, caisse de chargement ou bibliothèque partagée, ou intégré via les interfaces FFI, Protobuf et JSON. Il a un binaire séparé, sputnikvm-dev, destiné à des fins de test, qui émule la plupart de l’API JSON-RPC et de l’extraction de blocs.

Bibliothèques

web3.js

web3.js est l’API JavaScript compatible Ethereum pour communiquer avec les clients via JSON-RPC, développée par la Fondation Ethereum.

Référentiel de packages npm : https://www.npmjs.com/package/web3

Documentation pour l’API web3.js 0.2xx : http://bit.ly/2Qcyq1C

Documentation pour l’API web3.js 1.0.0-beta.xx : http://bit.ly/2CT33p0

web3.py

web3.py est une bibliothèque Python pour interagir avec la chaîne de blocs Ethereum, maintenue par la Fondation Ethereum.

Ethereum JS

EthereumJS est une collection de bibliothèques et d’utilitaires pour Ethereum.

web3j

web3j est une bibliothèque Java et Android pour l’intégration avec les clients Ethereum et l’utilisation de contrats intelligents.

Site Web : https://web3j.io

Documents : https://docs.web3j.io

EtherJar

EtherJar est une autre bibliothèque Java pour s’intégrer à Ethereum et travailler avec des contrats intelligents. Il est conçu pour les projets côté serveur basés sur Java 8+ et fournit un accès de bas niveau et un wrapper de haut niveau autour de RPC, des structures de données Ethereum et d’un accès aux contrats intelligents.

Nethereum

Nethereum est la bibliothèque d’intégration .Net pour Ethereum.

ethers.js

La bibliothèque ethers.js est une bibliothèque Ethereum compacte, complète et largement testée sous licence MIT, qui a reçu une subvention DevEx de la Fondation Ethereum pour son extension et sa maintenance.

Documentation : https://docs.ethers.io

Emerald Platform

Emerald Platform fournit des bibliothèques et des composants d’interface utilisateur pour créer des DApps au-dessus d’Ethereum. Emerald JS et Emerald JS UI fournissent des ensembles de modules et de composants React pour créer des applications et des sites Web JavaScript ; Emerald SVG Icons est un ensemble d’icônes liées aux chaînes de blocs. En plus des bibliothèques JavaScript, Emerald dispose d’une bibliothèque Rust pour exploiter les clés privées et les signatures de transaction. Toutes les bibliothèques et composantes Emerald sont sous licence Apache, version 2.0.

Documentation : https://docs.etcdevteam.com

Tester les contrats intelligents

Il existe plusieurs cadres de test couramment utilisés pour le développement de contrats intelligents, résumés dans Résumé des cadres de test des contrats intelligents :

Table 1. Résumé des cadres de test des contrats intelligents
Cadre Langue(s) d’essai Cadre de test Émulateur de chaîne Site Internet

Truffle

JavaScript/Solidity

Moka

TestRPC/Ganache

https://truffeframework.com/

Embark

JavaScript

Moka

TestRPC/Ganache

https://embark.status.im/docs/

DApp

Solidity

ds-test (personnalisé)

ethrun (Parity)

https://dapp.tools/dapp/

Populus

Python

pytest

Émulateur de chaîne Python

https://populus.readthedocs.io

Truffle

Truffle permet d’écrire des tests unitaires en JavaScript (basé sur Mocha) ou Solidity. Ces tests sont exécutés contre Ganache.

Embark

Embark s’intègre à Mocha pour exécuter des tests unitaires écrits en JavaScript. Les tests sont à leur tour exécutés sur des contrats déployés sur TestRPC/Ganache. Le framework Embark déploie automatiquement les contrats intelligents et redéploie automatiquement les contrats lorsqu’ils sont modifiés. Il assure également le suivi des contrats déployés et ne déploie les contrats que lorsque cela est vraiment nécessaire. Embark inclut une bibliothèque de test pour exécuter et tester rapidement vos contrats dans un EVM, avec des fonctions comme assert.equal. La commande embark test exécutera tous les fichiers de test sous le répertoire test.

Dapp

Dapp utilise le code Solidity natif (une bibliothèque appelée ds-test)et une bibliothèque Rust construite par Parity appelée ethrun pour exécuter le code intermédiaire Ethereum, puis affirmer l’exactitude. La bibliothèque ds-test fournit des fonctions d’assertion pour valider l’exactitude et les événements pour la journalisation des données dans la console.

Les fonctions d’assertion incluent :

assert(bool condition)
assertEq(address a, address b)
assertEq(bytes32 a, bytes32 b)
assertEq(int a, int b)
assertEq(uint a, uint b)
assertEq0(bytes a, bytes b)
expectEventsExact(address target)

Les commandes de journalisation consigneront les informations dans la console, ce qui les rendra utiles pour le débogage :

logs(bytes)
log_bytes32(bytes32)
log_named_bytes32(bytes32 key, bytes32 val)
log_named_address(bytes32 key, address val)
log_named_int(bytes32 key, int val)
log_named_uint(bytes32 key, uint val)
log_named_decimal_int(bytes32 key, int val, uint decimals)
log_named_decimal_uint(bytes32 key, uint val, uint decimals)
Populus

Populus utilise Python et son propre émulateur de chaîne pour exécuter des contrats écrits en Solidity. Les tests unitaires sont écrits en Python avec la bibliothèque pytest. Populus prend en charge la rédaction de contrats spécifiquement pour les tests. Ces noms de fichiers de contrat doivent correspondre au modèle global Test*.sol et se trouver n’importe où dans le répertoire des tests du projet, tests.

Test embarqué sur la chaîne de blocs

Bien que la plupart des tests ne devraient pas avoir lieu sur les contrats déployés, le comportement d’un contrat peut être vérifié via les clients Ethereum. Les commandes suivantes peuvent être utilisées pour évaluer l’état d’un contrat intelligent. Ces commandes doivent être tapées sur le terminal geth, bien que n’importe quelle console web3 les prenne également en charge.

Pour obtenir l’adresse d’un contrat à txhash, utilisez :

web3.eth.getTransactionReceipt(txhash);

Cette commande obtient le code d’un contrat déployé à contractaddress ; cela peut être utilisé pour vérifier le bon déploiement :

web3.eth.getCode(contractaddress)

Cela permet d’obtenir les journaux complets du contrat situé à l’adresse spécifiée dans options, ce qui est utile pour afficher l’historique des appels d’un contrat :

web3.eth.getPastLogs(options)

Enfin, cette commande obtient le stockage situé à address avec un décalage de position :

web3.eth.getStorageAt(address, position)

Ganache : une chaîne de blocs de test locale

Ganache est une chaîne de blocs de test locale que vous pouvez utiliser pour déployer des contrats, développer vos applications et exécuter des tests. Il est disponible en tant qu’application de bureau (avec une interface utilisateur graphique) pour Windows, macOS et Linux. Il est également disponible sous la forme d’un utilitaire de ligne de commande appelé ganache-cli. Pour plus de détails et des instructions d’installation pour l’application de bureau Ganache, voir https://truffleframework.com/ganache.

Le code ganache-cli peut être trouvé sur https://github.com/trufflesuite/ganache-cli/.

Pour installer la ligne de commande ganache-cli, utilisez npm :

$ npm install -g ganache-cli

Vous pouvez utiliser ganache-cli pour démarrer une chaîne de blocs locale à tester comme suit :

$ ganache-cli \
  --networkId=3 \
  --port="8545" \
  --verbose \
  --gasLimit=8000000 \
  --gasPrice=4000000000;

Quelques notes sur cette ligne de commande :

  • ❏ Vérifiez que les valeurs des indicateurs --networkId et --port correspondent à votre configuration dans truffle.js.

  • ❏ Vérifiez que la valeur de l’indicateur --gasLimit correspond à la dernière limite de gaz du réseau principal (par exemple, 8 000 000 de gaz) indiquée sur https://ethstats.net pour éviter de rencontrer inutilement des exceptions «hors de gaz». Notez qu’un --gasPrice de 4000000000 représente un prix du gaz de 4 gwei.

  • ❏ Vous pouvez éventuellement saisir une valeur d’indicateur --mnemonic pour restaurer un portefeuille HD précédent et les adresses associées.