Interagir avec d'autres contrats depuis Solidity
Dans les tutoriels précédents, nous avons beaucoup appris sur comment déployer votre premier contrat intelligent, comment y ajouter certaines fonctionnalités comme le contrôle d'accès avec des modificateurs (opens in a new tab) ou la gestion des erreurs dans Solidity (opens in a new tab). Dans ce tutoriel, nous allons apprendre comment déployer un contrat intelligent à partir d'un contrat existant et interagir avec celui-ci.
Nous allons créer un contrat qui permet à quiconque d'avoir son propre contrat intelligent Counter en créant une fabrique pour celui-ci. Son nom sera CounterFactory. Voici d'abord le code de notre contrat intelligent Counter initial :
1pragma solidity 0.5.17;23contract Counter {45 uint256 private _count;6 address private _owner;7 address private _factory;8910 modifier onlyOwner(address caller) {11 require(caller == _owner, "Vous n'êtes pas le propriétaire du contrat");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "Vous devez utiliser la fabrique");17 _;18 }1920 constructor(address owner) public {21 _owner = owner;22 _factory = msg.sender;23 }2425 function getCount() public view returns (uint256) {26 return _count;27 }2829 function increment(address caller) public onlyFactory onlyOwner(caller) {30 _count++;31 }3233}Afficher toutNotez que nous avons légèrement modifié le code du contrat pour garder une trace de l'adresse de la fabrique et de l'adresse du propriétaire du contrat. Lorsque vous appelez un code de contrat depuis un autre contrat, msg.sender fera référence à l'adresse de notre fabrique de contrats. C'est un point vraiment important à comprendre, car l'utilisation d'un contrat pour interagir avec d'autres contrats est une pratique courante. Vous devez donc faire attention à qui est l'expéditeur dans les cas complexes.
Pour cela, nous avons également ajouté un modificateur onlyFactory qui s'assure que la fonction de changement d'état ne peut être appelée que par la fabrique qui transmettra l'appelant original en tant que paramètre.
À l'intérieur de notre nouvelle CounterFactory qui gérera tous les autres contrats Compteur, nous ajouterons un mapping qui associera un propriétaire à l'adresse de son contrat Compteur :
1mapping(address => Counter) _counters;Dans Ethereum, les mappings sont l'équivalent des objets en JavaScript. Ils permettent de mapper une clé de type A à une valeur de type B. Dans ce cas, nous mappons l'adresse d'un propriétaire avec l'instance de son Compteur.
Instancier un nouveau Compteur pour quelqu'un ressemblera à ceci :
1 function createCounter() public {2 require (_counters[msg.sender] == Counter(0));3 _counters[msg.sender] = new Counter(msg.sender);4 }Nous vérifions d'abord si la personne possède déjà un Compteur. S'il ne possède pas de Compteur, nous instancions un nouveau Compteur en passant son adresse au constructeur Counter et nous assignons l'instance nouvellement créée au mapping.
Pour obtenir la valeur d'un Compteur spécifique, cela ressemblera à ceci :
1function getCount(address account) public view returns (uint256) {2 require (_counters[account] != Counter(0));3 return (_counters[account].getCount());4}56function getMyCount() public view returns (uint256) {7 return (getCount(msg.sender));8}La première fonction vérifie si le contrat Compteur existe pour une adresse donnée, puis appelle la méthode getCount depuis l'instance. La deuxième fonction, getMyCount, est juste un raccourci pour passer directement msg.sender à la fonction getCount.
La fonction increment est assez similaire, mais elle transmet l'expéditeur de la transaction originale au contrat Counter :
1function increment() public {2 require (_counters[msg.sender] != Counter(0));3 Counter(_counters[msg.sender]).increment(msg.sender);4 }Notez que s'il est appelé trop de fois, notre compteur pourrait être victime d'un dépassement de capacité (overflow). Vous devriez utiliser la bibliothèque SafeMath (opens in a new tab) autant que possible pour vous protéger de ce cas de figure.
Pour déployer notre contrat, vous devrez fournir à la fois le code de CounterFactory et de Counter. Lors du déploiement, dans Remix par exemple, vous devrez sélectionner CounterFactory.
Voici le code complet :
1pragma solidity 0.5.17;23contract Counter {45 uint256 private _count;6 address private _owner;7 address private _factory;8910 modifier onlyOwner(address caller) {11 require(caller == _owner, "Vous n'êtes pas le propriétaire du contrat");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "Vous devez utiliser la fabrique");17 _;18 }1920 constructor(address owner) public {21 _owner = owner;22 _factory = msg.sender;23 }2425 function getCount() public view returns (uint256) {26 return _count;27 }2829 function increment(address caller) public onlyFactory onlyOwner(caller) {30 _count++;31 }3233}3435contract CounterFactory {3637 mapping(address => Counter) _counters;3839 function createCounter() public {40 require (_counters[msg.sender] == Counter(0));41 _counters[msg.sender] = new Counter(msg.sender);42 }4344 function increment() public {45 require (_counters[msg.sender] != Counter(0));46 Counter(_counters[msg.sender]).increment(msg.sender);47 }4849 function getCount(address account) public view returns (uint256) {50 require (_counters[account] != Counter(0));51 return (_counters[account].getCount());52 }5354 function getMyCount() public view returns (uint256) {55 return (getCount(msg.sender));56 }5758}Afficher toutAprès compilation, dans la section de déploiement de Remix, vous sélectionnerez la fabrique à déployer :
Ensuite, vous pouvez vous amuser avec votre fabrique de contrats et vérifier que la valeur change. Si vous souhaitez appeler le contrat intelligent à partir d'une adresse différente, vous devrez changer l'adresse dans la sélection de compte de Remix.
Dernière mise à jour de la page : 15 août 2023
