{"id":846,"date":"2022-10-09T17:11:22","date_gmt":"2022-10-09T15:11:22","guid":{"rendered":"https:\/\/corsaire-consulting.fr\/blog\/?p=846"},"modified":"2022-10-09T17:18:39","modified_gmt":"2022-10-09T15:18:39","slug":"solidity-creer-un-smart-contract-evolutif","status":"publish","type":"post","link":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/2022\/10\/09\/solidity-creer-un-smart-contract-evolutif\/","title":{"rendered":"Solidity &#8211; Cr\u00e9er un smart contract \u00e9volutif"},"content":{"rendered":"<p>Les <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Contrat_intelligent\" target=\"_blank\" rel=\"noopener\"><em>smart contracts<\/em><\/a> d\u00e9ploy\u00e9s sur la blockchain Ethereum sont par natures immuables, c&rsquo;est \u00e0 dire qu&rsquo;on ne peut en faire \u00e9voluer le code source. Dans le contexte du d\u00e9veloppement d&rsquo;une application distribu\u00e9e (<a href=\"https:\/\/journalducoin.com\/lexique\/dapp\/\" target=\"_blank\" rel=\"noopener\">DApp<\/a>) ceci n&rsquo;est pas concevable.<br \/>\nLe cycle de vie de l&rsquo;application n\u00e9cessite obligatoirement de pouvoir faire \u00e9voluer le code source d&rsquo;un <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Contrat_intelligent\" target=\"_blank\" rel=\"noopener\"><em>smart contract<\/em><\/a> en vue de corriger des bugs ou int\u00e9grer de nouvelles \u00e9volutions fonctionnelles ou techniques.<\/p>\n<p>Cet article pr\u00e9sente une solution bas\u00e9e sur les outils <a href=\"https:\/\/docs.openzeppelin.com\/\" target=\"_blank\" rel=\"noopener\">OpenZepplin<\/a> pour construire et d\u00e9ployer un <a href=\"https:\/\/fr.wikipedia.org\/wiki\/Contrat_intelligent\" target=\"_blank\" rel=\"noopener\"><em>smart contract<\/em><\/a> puis ensuite le faire \u00e9voluer.<\/p>\n<p><!--more Lire la suite--><\/p>\n<p>Personnellement, j&rsquo;ai r\u00e9alis\u00e9 cette int\u00e9gration avec Ganache et Truffle mais rien ne vous emp\u00eache d&rsquo;utiliser d&rsquo;autres outils comme Hardhat par exemple.<\/p>\n<h2>Principe g\u00e9n\u00e9ral<\/h2>\n<p>En tout \u00e9tat de cause il n&rsquo;est pas possible de modifier un <em>smart contract<\/em> (SC) d\u00e9ploy\u00e9 sur la blockchain. La solution technique qui permet son \u00e9volution est de placer devant le <em>smart contract<\/em> <span style=\"text-decoration: underline;\">un proxy<\/span>. TOUS les appels passent par le proxy qui les redirigent automatiquement et de mani\u00e8re transparente vers le <em>smart contract<\/em>.<\/p>\n<p>Pour mettre \u00e0 jour le code du <em>smart contract<\/em> il faut donc :<\/p>\n<ul>\n<li>D\u00e9ployer une nouvelle version du <em>smart contract<\/em><\/li>\n<li>Modifier le Proxy pour qu&rsquo;il renvoie les appels vers la bonne version<\/li>\n<\/ul>\n<p>L&rsquo;outillage OpenZepplin prend tout en charge ce qui simplifie grandement l&rsquo;effort \u00e0 produire pour atteindre l&rsquo;objectif.<br \/>\nEn fait, 3 <em>smart contracts<\/em> seront d\u00e9ploy\u00e9s :<\/p>\n<ul>\n<li>Un <em>smart contract<\/em> pour notre impl\u00e9mentation<\/li>\n<li>Un <em>smart contract<\/em> proxy (OpenZepplin)<\/li>\n<li>Un <em>smart contract<\/em> d&rsquo;administratiuon du proxy (OpenZepplin)<\/li>\n<\/ul>\n<h2>D\u00e9veloppement<\/h2>\n<p>La suite de l&rsquo;article montre la mise \u00e0 jour d&rsquo;un <em>smart contract<\/em> d\u00e9ploy\u00e9 localement sur Ganache.<\/p>\n<p>Une premi\u00e8re version est d\u00e9ploy\u00e9e, puis une 2\u00e8me et enfin une 3\u00e8me.<\/p>\n<h3>Version 1<\/h3>\n<p>La version initiale du <em>smart contract<\/em> contient simplement une valeur qu&rsquo;il est possible de mettre \u00e0 jour ainsi qu&rsquo;un constructeur :<\/p>\n<p>[pastacode lang=\u00a0\u00bbjavascript\u00a0\u00bb manual=\u00a0\u00bb%2F%2F%20SPDX-License-Identifier%3A%20MIT%0Apragma%20solidity%20%3E%3D0.4.22%20%3C0.9.0%3B%0A%20%0A%2F%2F%2F%20%40author%20Emmanuel%20Collin%0A%2F%2F%2F%20%40notice%0A%2F%2F%2F%20%40dev%0Acontract%20MyContractV1%20%20%7B%0A%20%0A%20%20%20%20uint%20private%20value%3D0%3B%0A%20%0A%20%20%20%20constructor(uint%20v)%20%7B%0A%20%20%20%20%20%20%20%20setValue(v)%3B%0A%20%0A%20%20%20%20%7D%0A%20%0A%20%20%20%20function%20getValue()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%7D%0A%20%0A%20%20%20%20function%20setValue(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20value%20%3D%20v%3B%0A%20%20%20%20%7D%0A%20%0A%7D%0A\u00a0\u00bb message=\u00a0\u00bbSmart Contract version 1&Prime; highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h3>D\u00e9ploiement<\/h3>\n<p>Le <em>smart contract<\/em> est d\u00e9ploy\u00e9 avec la valeur initiale de 100.<\/p>\n<p>[pastacode lang=\u00a0\u00bbjavascript\u00a0\u00bb manual=\u00a0\u00bb%2F%2F%202_deploy_contracts.js%0Aconst%20MYCONTRACTV1%20%3D%20artifacts.require(%22.%2FMyContractV1.sol%22)%3B%0A%0Amodule.exports%20%3D%20async(deployer)%20%3D%3E%20%7B%0A%0A%20%20await%20deployer.deploy(MYCONTRACTV1%2C%20100)%3B%0A%20%20const%20contractInstance%20%3D%20await%20MYCONTRACTV1.deployed()%3B%0A%20%20console.log(%22V1%20Smart%20Contract%20address%20%3A%20%22%2CcontractInstance.address)%3B%0A%0A%20%20return%20null%3B%0A%7D%3B%0A\u00a0\u00bb message=\u00a0\u00bbD\u00e9ploiement de la version 1&Prime; highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h4>Tests<\/h4>\n<p>Utiliser la console Truffle pour tester la version 1 :<\/p>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20const%20contractV1%20%3D%20await%20MyContractV1.deployed(100)%3B%20%0A%20(await%20contractV1.getValue()).toString()%3Bundefined%20%0Atruffle(ganache)%3E%20%20(await%20contractV1.getValue()).toString()%3B%20%0A&rsquo;100&rsquo;%20%0Atruffle(ganache)%3E\u00a0\u00bb message=\u00a0\u00bb\u00a0\u00bb highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>Tout est OK, passons \u00e0 la version 2.<\/p>\n<h3>Version 1 en mode \u00e9volutif (<em>Upgradable Smart Contract<\/em>)<\/h3>\n<p>Avant de d\u00e9ployer la version 2 il y a quelques \u00e9tapes \u00e0 suivre pour rendre notre SC \u00e9volutif et compatible avec les outils OpenZepplin.<\/p>\n<h4>Installation du plugin OpenZepplin pour Truffle<\/h4>\n<p>Il faut installer le plugin pour Truffle qui prendra en charge le travail pour nous :<\/p>\n<p><span style=\"font-family: Courier New;\">npm install &#8211;save-dev @openzeppelin\/truffle-upgrades <\/span><\/p>\n<p>[pastacode lang=\u00a0\u00bbmarkup\u00a0\u00bb manual=\u00a0\u00bbnpm%20install%20&#8211;save-dev%20%40openzeppelin%2Ftruffle-upgrades%20%0Anpm%20WARN%20deprecated%20uuid%403.3.2%3A%20Please%20upgrade%20%20to%20version%207%20or%20higher.%20%20Older%20versions%20may%20use%20Math.random()%20in%20certain%20circumstances%2C%20which%20is%20known%20to%20be%20problematic.%20%20See%20https%3A%2F%2Fv8.dev%2Fblog%2Fmath-random%20for%20details.%20%0A%0Aadded%20441%20packages%2C%20removed%2023%20packages%2C%20changed%2054%20packages%2C%20and%20audited%201535%20packages%20in%2043s%20%0A%0A139%20packages%20are%20looking%20for%20funding%20%0A%20%20run%20%60npm%20fund%60%20for%20details%20%0A%0A35%20vulnerabilities%20(23%20moderate%2C%209%20high%2C%203%20critical)%20%0A%0ATo%20address%20issues%20that%20do%20not%20require%20attention%2C%20run%3A%20%0A%20%20npm%20audit%20fix%20%0A%0ASome%20issues%20need%20review%2C%20and%20may%20require%20choosing%20%0Aa%20different%20dependency.%20%0A%0ARun%20%60npm%20audit%60%20for%20details.%20&Prime; message=\u00a0\u00bbInstallation plugin pour Truffle\u00a0\u00bb highlight=\u00a0\u00bb1&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h4>Modifier le code source<\/h4>\n<p>Il y a 2 petites \u00e9volutions \u00e0 faire sur le code de la version 1 pour qu&rsquo;elle puisse \u00eatre prise en compte par le plugin :<\/p>\n<ul>\n<li>Supprimer le constructeur. Il est remplacer par une fonction (<strong>initialize()<\/strong> dans notre cas) qui fait le m\u00eame travail. Cette fonction sera appel\u00e9e par le plugin lors du d\u00e9ploiement.<\/li>\n<li>Supprimer l&rsquo;initialisation de la propri\u00e9t\u00e9 \u00ab\u00a0value\u00a0\u00bb<\/li>\n<\/ul>\n<p>[pastacode lang=\u00a0\u00bbjavascript\u00a0\u00bb manual=\u00a0\u00bb%2F%2F%20SPDX-License-Identifier%3A%20MIT%0Apragma%20solidity%20%3E%3D0.4.22%20%3C0.9.0%3B%0A%0A%2F%2F%2F%20%40author%20Emmanuel%20Collin%0A%2F%2F%2F%20%40notice%0A%2F%2F%2F%20%40dev%0Acontract%20MyContractV1%20%20%7B%0A%0A%20%20%20%20uint%20private%20value%3B%0A%0A%20%20%20%20function%20initialize(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(v)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20getValue()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20setValue(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20value%20%3D%20v%3B%0A%20%20%20%20%7D%0A%0A%7D%0A\u00a0\u00bb message=\u00a0\u00bbVersion 1 en mode \u00e9volutif\u00a0\u00bb highlight=\u00a0\u00bb9,11,12,13&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>Les d\u00e9tails au sujet de ces 2 modifications sont donn\u00e9s dans ce chapitre de la <a href=\"https:\/\/docs.openzeppelin.com\/learn\/upgrading-smart-contracts?pref=hardhat#initialization\" target=\"_blank\" rel=\"noopener\">documentation du plugin<\/a>.<\/p>\n<h4>D\u00e9ploiement de la version 1<\/h4>\n<p>Le code de d\u00e9ploiement \u00e9volue aussi sensiblement pour utiliser le plugin :<\/p>\n<p>[pastacode lang=\u00a0\u00bbmarkup\u00a0\u00bb manual=\u00a0\u00bb%2F%2F%20migrations%2F3_deploy_upgradeable_contract.js%0Aconst%20%7B%20deployProxy%20%7D%20%3D%20require(&lsquo;%40openzeppelin%2Ftruffle-upgrades&rsquo;)%3B%0A%0Aconst%20MyContractV1%20%3D%20artifacts.require(&lsquo;MyContractV1&rsquo;)%3B%0A%0Amodule.exports%20%3D%20async%20function%20(deployer)%20%7B%0A%20%20await%20deployProxy(MyContractV1%2C%20%5B142%5D%2C%20%7B%20deployer%2C%20initializer%3A%20&rsquo;initialize&rsquo;%20%7D)%3B%0A%7D%3B\u00a0\u00bb message=\u00a0\u00bbD\u00e9ploiement de la version 2&Prime; highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>Cette fois le contrat sera d\u00e9ploy\u00e9 avec la valeur initiale 142.<\/p>\n<p>R\u00e9sultat du d\u00e9ploiement :<\/p>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bb&#8230;%0A3_deploy_upgradeable_contract.js%0A%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%0A%0A%20%20%20Replacing%20&rsquo;MyContractV1&rsquo;%0A%20%20%20&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200xd6e08f79b326fa0f2a1a6398418338dcb710f906b191236de0e68187ca6be940%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x9F4117A5a0cC73eAc3a6c136191FceCe2710bb72%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%209%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665324320%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x6742aF78E1E4Ba1883873bEf8DB4829FA0c28b4a%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.97878906%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20136669%20(0x215dd)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00273338%20ETH%0A%0A%0A%20%20%20Deploying%20&rsquo;ProxyAdmin&rsquo;%0A%20%20%20&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200x652c7944ce74a2a09eed25eb459bae6e238dbcbf93809fca2ffe2277b935bf29%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x96B5e8eB02fF5E0700732a8b6e931ABbCAE09e6c%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%2010%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665324321%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x6742aF78E1E4Ba1883873bEf8DB4829FA0c28b4a%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.96909372%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20484767%20(0x7659f)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00969534%20ETH%0A%0A%0A%20%20%20Deploying%20&rsquo;TransparentUpgradeableProxy&rsquo;%0A%20%20%20&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200xa085a64260fcf1ef09aaccf347fcaafa1c9fdcaeba4c9dafeef21724008414e4%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x67aa0b798C50EcD4320eFD8Ef0De03Fbe55D30c1%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%2011%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665324322%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x6742aF78E1E4Ba1883873bEf8DB4829FA0c28b4a%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.95696146%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20606613%20(0x94195)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.01213226%20ETH%0A%0A&#8230;%0A\u00a0\u00bb message=\u00a0\u00bbR\u00e9sultat du d\u00e9ploiement\u00a0\u00bb highlight=\u00a0\u00bb39&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>On constate bien le d\u00e9ploiement des 3 <em>smart contracts<\/em>.<\/p>\n<h4>Tests<\/h4>\n<h5>D\u00e9ploiement<\/h5>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20const%20contractV1%20%3D%20await%20MyContractV1.deployed()%3B%0Aundefined%0Atruffle(ganache)%3E%20contractV1.address%0A&rsquo;0x67aa0b798C50EcD4320eFD8Ef0De03Fbe55D30c1&rsquo;%0Atruffle(ganache)%3E\u00a0\u00bb message=\u00a0\u00bb\u00a0\u00bb highlight=\u00a0\u00bb4&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p><span style=\"color: #ff0000;\"><strong>L&rsquo;adresse de contractV1 est bien celle du proxy TransparentUpgradeableProxy !<\/strong><\/span><\/p>\n<h5>Invocation du SC via le proxy<\/h5>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20(await%20contractV1.getValue()).toString()%3B%0A&rsquo;142&prime;\u00a0\u00bb message=\u00a0\u00bbTest de la version 1 en mode proxy\u00a0\u00bb highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h3>Version 2<\/h3>\n<p>Nous pouvons maintenant passer \u00e0 la version 2 de notre <em>smart contract<\/em>. Le code source est modifi\u00e9 pour ajouter la fonction add() qui permet d&rsquo;ajouter un nombre \u00e0 la propri\u00e9t\u00e9 \u00ab\u00a0value\u00a0\u00bb.<\/p>\n<h4>D\u00e9veloppement<\/h4>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bb%2F%2F%20SPDX-License-Identifier%3A%20MIT%0Apragma%20solidity%20%3E%3D0.4.22%20%3C0.9.0%3B%0A%0A%2F%2F%2F%20%40author%20Emmanuel%20Collin%0A%2F%2F%2F%20%40notice%0A%2F%2F%2F%20%40dev%0Acontract%20MyContractV2%20%20%7B%0A%0A%20%20%20%20uint%20private%20value%3B%0A%0A%20%20%20%20function%20initialize(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(v)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20getValue()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20setValue(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20value%20%3D%20v%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20add(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(getValue()%20%2B%20v)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A\u00a0\u00bb message=\u00a0\u00bbVersion 2 du smart contract\u00a0\u00bb highlight=\u00a0\u00bb23,24,25&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h4>D\u00e9ploiement<\/h4>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbconst%20%7B%20upgradeProxy%20%7D%20%3D%20require(&lsquo;%40openzeppelin%2Ftruffle-upgrades&rsquo;)%3B%0A%0Aconst%20MyContractV1%20%3D%20artifacts.require(&lsquo;MyContractV1&rsquo;)%3B%0Aconst%20MyContractV2%20%3D%20artifacts.require(&lsquo;MyContractV2&rsquo;)%3B%0A%0Amodule.exports%20%3D%20async%20function%20(deployer)%20%7B%0A%20%20const%20existing%20%3D%20await%20MyContractV1.deployed()%3B%0A%20%20await%20upgradeProxy(existing.address%2C%20MyContractV2%2C%20%7B%20deployer%20%7D)%3B%0A%7D%3B\u00a0\u00bb message=\u00a0\u00bbD\u00e9ploiement de la version 2&Prime; highlight=\u00a0\u00bb7,8&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>A la ligne 7, on r\u00e9cup\u00e8re l&rsquo;adresse du proxy (existing)<\/p>\n<p>A la ligne 8 on modifie le proxy pour d\u00e9ployer la version 2 et pointer dessus.<\/p>\n<p>[pastacode lang=\u00a0\u00bbmarkup\u00a0\u00bb manual=\u00a0\u00bb3_deploy_upgradeable_contract.js%0A%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%0A%0A%20%20%20Replacing%20&rsquo;MyContractV1&rsquo;%0A%20%20%20&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200xe0446bf8aa2e00f93952e1f9a27dc0aea46a3f26f3efdf1329764649242f682a%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200xf778A97f5840281122061a52F33585F719E8f4c2%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%205%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665325731%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x0381962bD9B48A87534f6F7C2ceFCAE2b2E87EA0%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.98815564%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20136669%20(0x215dd)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00273338%20ETH%0A%0A%0A%20%20%20Deploying%20&rsquo;ProxyAdmin&rsquo;%0A%20%20%20&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200x53f9fb7b22ad68171fb06308793d6c9f1b256b7ec9b96733416ab021ee029d08%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200xCE4Bd3A1f2a37378D30f017db906E57bd6bf1824%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%206%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665325731%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x0381962bD9B48A87534f6F7C2ceFCAE2b2E87EA0%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.9784603%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20484767%20(0x7659f)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00969534%20ETH%0A%0A%0A%20%20%20Deploying%20&rsquo;TransparentUpgradeableProxy&rsquo;%0A%20%20%20&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200x6c1a80930a171491d9d45d96a8d61ad18cd9bc9546a88fd9106a3adf26291688%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x34275c222Cf18e28EbB1ecBc7c4b23aDd4baEbE7%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%207%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665325732%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x0381962bD9B48A87534f6F7C2ceFCAE2b2E87EA0%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.9663278%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20606625%20(0x941a1)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.0121325%20ETH%0A%0A%0A%20%20%20%3E%20Saving%20migration%20to%20chain.%0A%20%20%20%3E%20Saving%20artifacts%0A%20%20%20&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-%0A%20%20%20%3E%20Total%20cost%3A%20%20%20%20%20%20%20%20%20%200.02456122%20ETH%0A%0A%0A4_deploy_upgradeable_contract_v2.js%0A%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%3D%0A%0A%20%20%20Replacing%20&rsquo;MyContractV2&rsquo;%0A%20%20%20&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;%0A%20%20%20%3E%20transaction%20hash%3A%20%20%20%200xc5231aa4c55e56fa66e4e8caf397f7669fdbd34c768e09a9507ff8c2e0a1986c%0A%20%20%20%3E%20Blocks%3A%200%20%20%20%20%20%20%20%20%20%20%20%20Seconds%3A%200%0A%20%20%20%3E%20contract%20address%3A%20%20%20%200x44A6b605696cB63ABc6d1670896ae38dF6988C6F%0A%20%20%20%3E%20block%20number%3A%20%20%20%20%20%20%20%209%0A%20%20%20%3E%20block%20timestamp%3A%20%20%20%20%201665325734%0A%20%20%20%3E%20account%3A%20%20%20%20%20%20%20%20%20%20%20%20%200x0381962bD9B48A87534f6F7C2ceFCAE2b2E87EA0%0A%20%20%20%3E%20balance%3A%20%20%20%20%20%20%20%20%20%20%20%20%2099.96217872%0A%20%20%20%3E%20gas%20used%3A%20%20%20%20%20%20%20%20%20%20%20%20179941%20(0x2bee5)%0A%20%20%20%3E%20gas%20price%3A%20%20%20%20%20%20%20%20%20%20%2020%20gwei%0A%20%20%20%3E%20value%20sent%3A%20%20%20%20%20%20%20%20%20%200%20ETH%0A%20%20%20%3E%20total%20cost%3A%20%20%20%20%20%20%20%20%20%200.00359882%20ETH\u00a0\u00bb message=\u00a0\u00bbR\u00e9sultat du d\u00e9ploiement\u00a0\u00bb highlight=\u00a0\u00bb38&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h4>Tests<\/h4>\n<h5>D\u00e9ploiement<\/h5>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20const%20contractV1%20%3D%20await%20MyContractV1.deployed()%3B%0Aundefined%0Atruffle(ganache)%3E%20const%20contractV2%20%3D%20await%20MyContractV2.at(contractV1.address)%3B%0Aundefined%0Atruffle(ganache)%3E%20contractV1.address%0A&rsquo;0x34275c222Cf18e28EbB1ecBc7c4b23aDd4baEbE7&rsquo;%0Atruffle(ganache)%3E%20contractV2.address%0A&rsquo;0x34275c222Cf18e28EbB1ecBc7c4b23aDd4baEbE7&prime;\u00a0\u00bb message=\u00a0\u00bbTests de la version 2&Prime; highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>L&rsquo;adresse de la version 2 est bien celle du proxy : &lsquo;0x34275c222Cf18e28EbB1ecBc7c4b23aDd4baEbE7&rsquo;<\/p>\n<h5>Invocation du <em>smart contract<\/em><\/h5>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20(await%20contractV2.getValue()).toString()%3B%0A&rsquo;142&prime;\u00a0\u00bb message=\u00a0\u00bbVersion 2 &#8211; Lecture de la valeur initiale\u00a0\u00bb highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20await%20contractV2.add(10)%3B%0A%7B%0A%20%20tx%3A%20&rsquo;0xaed8cbf957ca9909fce79a097f9fd99d751f30a30eedb86812c6d2354b190f1c&rsquo;%2C%0A%20%20receipt%3A%20%7B%0A%20%20%20%20transactionHash%3A%20&rsquo;0xaed8cbf957ca9909fce79a097f9fd99d751f30a30eedb86812c6d2354b190f1c&rsquo;%2C%0A%20%20%20%20transactionIndex%3A%200%2C%0A%20%20%20%20blockHash%3A%20&rsquo;0xfddc15ec6b90e71287d52ff3eae225024343c8b43b346e6fa1f5a23a838b8aa7&rsquo;%2C%0A%20%20%20%20blockNumber%3A%2012%2C%0A%20%20%20%20from%3A%20&rsquo;0x0381962bd9b48a87534f6f7c2cefcae2b2e87ea0&rsquo;%2C%0A%20%20%20%20to%3A%20&rsquo;0x34275c222cf18e28ebb1ecbc7c4b23add4baebe7&rsquo;%2C%0A%20%20%20%20gasUsed%3A%2030476%2C%0A%20%20%20%20cumulativeGasUsed%3A%2030476%2C%0A%20%20%20%20contractAddress%3A%20null%2C%0A%20%20%20%20logs%3A%20%5B%5D%2C%0A%20%20%20%20status%3A%20true%2C%0A%20%20%20%20logsBloom%3A%20&rsquo;0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000&rsquo;%2C%0A%20%20%20%20rawLogs%3A%20%5B%5D%0A%20%20%7D%2C%0A%20%20logs%3A%20%5B%5D%0A%7D\u00a0\u00bb message=\u00a0\u00bbVersion 2 &#8211; Appel de la fonction add()\u00a0\u00bb highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20(await%20contractV2.getValue()).toString()%3B%0A&rsquo;152&prime;\u00a0\u00bb message=\u00a0\u00bbVersion 2 &#8211; V\u00e9rification de la nouvelle valeur\u00a0\u00bb highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h4>Remarques :<\/h4>\n<p><span style=\"text-decoration: underline;\">Que se passe-t-il si on appelle la fonction add() depuis contractV1 ?<\/span><\/p>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20await%20contractV1.add(10)%3B%0AUncaught%20TypeError%3A%20contractV1.add%20is%20not%20a%20function%0A%20%20%20%20at%20evalmachine.%3Canonymous%3E%3A1%3A20&Prime; message=\u00a0\u00bbAppel de la fonction add() depuis la version 1&Prime; highlight=\u00a0\u00bb2&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>Une erreur \u00e9videment, la fonction add() n&rsquo;existe pas sur cette version.<\/p>\n<p><span style=\"text-decoration: underline;\">Que renvoie la fonction getValue() appel\u00e9e depuis la version 1 ?<\/span><\/p>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20(await%20contractV1.getValue()).toString()%3B%0A&rsquo;152&prime;\u00a0\u00bb message=\u00a0\u00bb\u00a0\u00bb highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p>Elle renvoie la m\u00eame chose ce qui confirme que <strong>les 2 versions partagent le m\u00eame contexte, les m\u00eames donn\u00e9es.<\/strong><\/p>\n<h3>Version 3<\/h3>\n<p>La version 3 vise \u00e0 ajouter une nouvelle donn\u00e9e (propri\u00e9t\u00e9) au <em>smart contract<\/em> (count) ainsi qu&rsquo;une fonction pour en consulter la valeur (getCount). \u00ab\u00a0count\u00a0\u00bb est un entier qui est incr\u00e9ment\u00e9 automatiquement \u00e0 chaque fois que la valeur de la propri\u00e9t\u00e9 <em>value<\/em> change.<\/p>\n<h4>D\u00e9veloppement<\/h4>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bb%2F%2F%20SPDX-License-Identifier%3A%20MIT%0Apragma%20solidity%20%3E%3D0.4.22%20%3C0.9.0%3B%0A%0A%2F%2F%2F%20%40author%20Emmanuel%20Collin%0A%2F%2F%2F%20%40notice%0A%2F%2F%2F%20%40dev%0Acontract%20MyContractV3%20%20%7B%0A%0A%20%20%20%20uint%20private%20value%3B%0A%20%20%20%20uint%20private%20count%3B%0A%0A%20%20%20%20function%20initialize(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(v)%3B%0A%20%20%20%20%20%20%20%20count%20%3D%200%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20getValue()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20value%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20setValue(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20value%20%3D%20v%3B%0A%20%20%20%20%20%20%20%20count%2B%2B%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20add(uint%20v)%20public%20%7B%0A%20%20%20%20%20%20%20%20setValue(getValue()%20%2B%20v)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20getCount()%20public%20view%20returns%20(uint)%20%7B%0A%20%20%20%20%20%20%20%20return%20count%3B%0A%20%20%20%20%7D%0A%0A%7D%0A\u00a0\u00bb message=\u00a0\u00bbVersion 3 du smart contract\u00a0\u00bb highlight=\u00a0\u00bb10,30,31,32&Prime; provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h4>D\u00e9ploiement<\/h4>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbconst%20%7B%20upgradeProxy%20%7D%20%3D%20require(&lsquo;%40openzeppelin%2Ftruffle-upgrades&rsquo;)%3B%0A%0Aconst%20MyContractV1%20%3D%20artifacts.require(&lsquo;MyContractV1&rsquo;)%3B%0Aconst%20MyContractV3%20%3D%20artifacts.require(&lsquo;MyContractV3&rsquo;)%3B%0A%0Amodule.exports%20%3D%20async%20function%20(deployer)%20%7B%0A%20%20const%20existing%20%3D%20await%20MyContractV1.deployed()%3B%0A%20%20await%20upgradeProxy(existing.address%2C%20MyContractV3%2C%20%7B%20deployer%20%7D)%3B%0A%7D%3B\u00a0\u00bb message=\u00a0\u00bbD\u00e9ploiement de la version 3&Prime; highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<h4>Tests<\/h4>\n<p>[pastacode lang=\u00a0\u00bbbash\u00a0\u00bb manual=\u00a0\u00bbtruffle(ganache)%3E%20const%20contractV1%20%3D%20await%20MyContractV1.deployed()%3B%0Aundefined%0Atruffle(ganache)%3E%20const%20contractV2%20%3D%20await%20MyContractV2.at(contractV1.address)%3B%0Aundefined%0Atruffle(ganache)%3E%20const%20contractV3%20%3D%20await%20MyContractV3.at(contractV1.address)%3B%0Aundefined%0Atruffle(ganache)%3E%20contractV1.address%0AcontractV2.address%0AcontractV3.address%0A&rsquo;0xfF8b6f16Bedb4FF11098Ab06649Ddd0B0c8A9720&rsquo;%0Atruffle(ganache)%3E%20&rsquo;0xfF8b6f16Bedb4FF11098Ab06649Ddd0B0c8A9720&rsquo;%0Atruffle(ganache)%3E%20&rsquo;0xfF8b6f16Bedb4FF11098Ab06649Ddd0B0c8A9720&rsquo;%0Atruffle(ganache)%3E%20(await%20contractV3.getValue()).toString()%3B%0A&rsquo;142&rsquo;%0Atruffle(ganache)%3E%20(await%20contractV3.getCount()).toString()%3B%0A&rsquo;0&rsquo;%0Atruffle(ganache)%3E%20await%20contractV3.add(10)%3B%0A%7B%0A%20%20tx%3A%20&rsquo;0xffef16f8589b23cece9348a6d248c16a663082a74b55b022128548c382da0731&rsquo;%2C%0A%20%20receipt%3A%20%7B%0A%20%20%20%20transactionHash%3A%20&rsquo;0xffef16f8589b23cece9348a6d248c16a663082a74b55b022128548c382da0731&rsquo;%2C%0A%20%20%20%20transactionIndex%3A%200%2C%0A%20%20%20%20blockHash%3A%20&rsquo;0x3fc626025cee38042d88556d35fa546b656fcf22487c1a7afcde635bba533176&rsquo;%2C%0A%20%20%20%20blockNumber%3A%2015%2C%0A%20%20%20%20from%3A%20&rsquo;0x21a554540e9a005ef517a2bbe7e3a447aa64290f&rsquo;%2C%0A%20%20%20%20to%3A%20&rsquo;0xff8b6f16bedb4ff11098ab06649ddd0b0c8a9720&rsquo;%2C%0A%20%20%20%20gasUsed%3A%2051436%2C%0A%20%20%20%20cumulativeGasUsed%3A%2051436%2C%0A%20%20%20%20contractAddress%3A%20null%2C%0A%20%20%20%20logs%3A%20%5B%5D%2C%0A%20%20%20%20status%3A%20true%2C%0A%20%20%20%20logsBloom%3A%20&rsquo;0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000&rsquo;%2C%0A%20%20%20%20rawLogs%3A%20%5B%5D%0A%20%20%7D%2C%0A%20%20logs%3A%20%5B%5D%0A%7D%0Atruffle(ganache)%3E%20(await%20contractV3.getValue()).toString()%3B%0A&rsquo;152&rsquo;%0Atruffle(ganache)%3E%20(await%20contractV3.getCount()).toString()%3B%0A&rsquo;1&rsquo;%0Atruffle(ganache)%3E\u00a0\u00bb message=\u00a0\u00bbTests de la version 3&Prime; highlight=\u00a0\u00bb\u00a0\u00bb provider=\u00a0\u00bbmanual\u00a0\u00bb\/]<\/p>\n<p><strong>All good !<\/strong><\/p>\n<h2>R\u00e9f\u00e9rences<\/h2>\n<ul>\n<li><a href=\"https:\/\/soliditylang.org\/\" target=\"_blank\" rel=\"noopener\">Solidity<\/a><\/li>\n<li><a href=\"https:\/\/docs.soliditylang.org\/en\/v0.8.17\/\" target=\"_blank\" rel=\"noopener\">Documentation langage Solidity<\/a><\/li>\n<li><a href=\"https:\/\/trufflesuite.com\/ganache\/\" target=\"_blank\" rel=\"noopener\">Ganache<\/a><\/li>\n<li><a href=\"https:\/\/trufflesuite.com\/truffle\/\" target=\"_blank\" rel=\"noopener\">Truffle<\/a><\/li>\n<li><a href=\"https:\/\/docs.openzeppelin.com\/upgrades\" target=\"_blank\" rel=\"noopener\">OpenZepplin &#8211; Outillage pour les smart contracts \u00e9volutifs<\/a><\/li>\n<li><a href=\"https:\/\/docs.openzeppelin.com\/learn\/upgrading-smart-contracts?pref=truffle\" target=\"_blank\" rel=\"noopener\">OpenZepplin &#8211; Comment mettre \u00e0 jour un smart contract<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Les smart contracts d\u00e9ploy\u00e9s sur la blockchain Ethereum sont par natures immuables, c&rsquo;est \u00e0 dire qu&rsquo;on ne peut en faire \u00e9voluer le code source. Dans le contexte du d\u00e9veloppement d&rsquo;une application distribu\u00e9e (DApp) ceci n&rsquo;est pas concevable. Le cycle de vie de l&rsquo;application n\u00e9cessite obligatoirement de pouvoir faire \u00e9voluer le code source d&rsquo;un smart contract [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":847,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[123,124,122],"tags":[127,118,129,126,125,128],"class_list":["post-846","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blockchain","category-smart-contract","category-solidity","tag-blockchain","tag-developpement","tag-ganache","tag-smart-contract","tag-solidity","tag-truffle"],"_links":{"self":[{"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/posts\/846","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=846"}],"version-history":[{"count":17,"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/posts\/846\/revisions"}],"predecessor-version":[{"id":864,"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/posts\/846\/revisions\/864"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/media\/847"}],"wp:attachment":[{"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=846"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=846"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/corsaire-consulting.fr\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=846"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}