Interakce s dalšími kontrakty ze Solidity
V předchozích návodech jsme se toho hodně naučili jak nasadit svůj první chytrý kontrakt a přidat do něj některé funkce, jako je řízení přístupu pomocí modifikátorů (opens in a new tab) nebo zpracování chyb v Solidity (opens in a new tab). V tomto návodu se naučíme, jak nasadit chytrý kontrakt z existujícího kontraktu a jak s ním interagovat.
Vytvoříme kontrakt, který komukoli umožní mít svůj vlastní Counter chytrý kontrakt tím, že pro něj vytvoříme továrnu (factory). Její název bude CounterFactory. Nejdříve si ukážeme kód našeho původního Counter chytrého kontraktu:
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, "You're not the owner of the contract");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "You need to use the factory");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}Zobrazit všeVšimni si, že jsme mírně upravili kód kontraktu, abychom mohli sledovat adresu továrny a adresu vlastníka kontraktu. Když voláš kód kontraktu z jiného kontraktu, msg.sender bude odkazovat na adresu naší továrny na kontrakty. Toto je opravdu důležitý bod k pochopení, protože použití kontraktu k interakci s jinými kontrakty je běžnou praxí. Proto by sis měl v komplexních případech dávat pozor, kdo je odesílatel.
Z tohoto důvodu jsme také přidali modifikátor onlyFactory, který zajišťuje, že funkci měnící stav může volat pouze továrna, která předá původního volajícího jako parametr.
Do naší nové CounterFactory, která bude spravovat všechny ostatní čítače (Counters), přidáme mapování, které přiřadí vlastníka k adrese jeho kontraktu čítače:
1mapping(address => Counter) _counters;V Ethereu je mapování ekvivalentem objektů v javascriptu, umožňují mapovat klíč typu A na hodnotu typu B. V tomto případě mapujeme adresu vlastníka s instancí jeho Čítače (Counter).
Vytvoření instance nového čítače (Counter) pro někoho bude vypadat takto:
1 function createCounter() public {2 require (_counters[msg.sender] == Counter(0));3 _counters[msg.sender] = new Counter(msg.sender);4 }Nejdříve zkontrolujeme, zda daná osoba již nějaký čítač (counter) vlastní. Pokud čítač nevlastní, vytvoříme instanci nového čítače předáním jeho adresy do konstruktoru Counter a přiřadíme nově vytvořenou instanci do mapování.
Získání počtu pro konkrétní čítač (Counter) bude vypadat takto:
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}První funkce zkontroluje, zda kontrakt Čítače (Counter) existuje pro danou adresu, a poté zavolá metodu getCount z instance. Druhá funkce: getMyCount je jen zkratka pro přímé předání msg.sender do funkce getCount.
Funkce increment je poměrně podobná, ale předává původního odesílatele transakce do kontraktu Counter:
1function increment() public {2 require (_counters[msg.sender] != Counter(0));3 Counter(_counters[msg.sender]).increment(msg.sender);4 }Všimni si, že pokud se bude volat příliš často, může se náš čítač stát obětí přetečení (overflow). Pro ochranu před tímto možným případem bys měl co nejvíce používat knihovnu SafeMath (opens in a new tab).
Pro nasazení našeho kontraktu budeš muset poskytnout kód jak pro CounterFactory, tak pro Counter. Při nasazování například v Remixu budeš muset vybrat CounterFactory.
Zde je celý kód:
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, "You're not the owner of the contract");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "You need to use the factory");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}Zobrazit všePo zkompilování v sekci pro nasazení v Remixu vybereš továrnu (factory), která se má nasadit:
Poté si můžeš hrát s továrnou na kontrakty a sledovat, jak se mění hodnota. Pokud bys chtěl volat chytrý kontrakt z jiné adresy, budeš muset změnit adresu ve výběru účtu (Account) v Remixu.
Stránka naposledy aktualizována: 15. srpna 2023
