Salt la conținutul principal

Interacționează cu alte contracte din Solidity

contracte inteligentesolidityremixfabriciimplementarecombinabilitate
Avansat
jdourlens
EthereumDev(opens in a new tab)
5 aprilie 2020
4 minute de citit minute read
comp-tutorial-metadata-tip-author 0x19dE91Af973F404EDF5B4c093983a7c6E3EC8ccE

În tutorialele anterioare ai învățat multe: cum să implementezi primul tău contract inteligent și să adaugi câteva caracteristici la acesta precum controlul accesului cu modificatori(opens in a new tab) sau gestionarea erorilor în Solidity(opens in a new tab). În acest tutorial vei învăța cum să implementezi un contract inteligent dintr-un contract existent și să interacționezi cu acesta.

Vei crea un contract care permite oricui să aibă propriul contract inteligent Counter, creând o fabrică pentru acesta, numele ei va fi CounterFactory. În primul rând aici este codul contractului inteligent inițial Counter:

1pragma solidity 0.5.17;
2
3contract Counter {
4
5 uint256 private _count;
6 address private _owner;
7 address private _factory;
8
9
10 modifier onlyOwner(address caller) {
11 require(caller == _owner, "You're not the owner of the contract");
12 _;
13 }
14
15 modifier onlyFactory() {
16 require(msg.sender == _factory, "You need to use the factory");
17 _;
18 }
19
20 constructor(address owner) public {
21 _owner = owner;
22 _factory = msg.sender;
23 }
24
25 function getCount() public view returns (uint256) {
26 return _count;
27 }
28
29 function increment(address caller) public onlyFactory onlyOwner(caller) {
30 _count++;
31 }
32
33}
Afișează tot
Copiați

Reține că am modificat ușor codul contractului pentru a urmări adresa fabricii și adresa proprietarului contractului. Când apelezi un cod de contract dintr-un alt contract, msg.sender va face referire la adresa fabricii noastre de contracte. Acesta este un punct foarte important de înțeles, deoarece utilizarea unui contract pentru a interacționa cu alte contracte este o practică comună. Prin urmare, ar trebui să ai grijă de cine este expeditorul în cazuri complexe.

Pentru aceasta am adăugat și un modificator onlyFactory care se asigură că funcția de modificare a stării poate fi apelată doar de fabrică, care va transmite apelantul inițial ca parametru.

În interiorul noului nostru CounterFactory, care va gestiona toate celelalte contoare, vom adăuga o mapare care va asocia un proprietar la adresa contractului său:

1mapping(address => Counter) _counters;
Copiați

În Ethereum, maparea este echivalentă cu obiectele din javascript, acestea permit maparea unei chei de tip A la o valoare de tip B. În acest caz, vom mapa adresa unui proprietar cu instanța Counter-ului său.

Crearea unei instanțe de contor nou pentru cineva, va arăta astfel:

1 function createCounter() public {
2 require (_counters[msg.sender] == Counter(0));
3 _counters[msg.sender] = new Counter(msg.sender);
4 }
Copiați

Verificăm mai întâi dacă persoana deține deja un contor. Dacă nu deține un contor, creăm o nouă instanță de contor nou prin trecerea adresei sale la constructorul Counter și atribuim noua instanță creată la mapare.

Pentru a obține numărul unui contor specific, scriem:

1function getCount(address account) public view returns (uint256) {
2 require (_counters[account] != Counter(0));
3 return (_counters[account].getCount());
4}
5
6function getMyCount() public view returns (uint256) {
7 return (getCount(msg.sender));
8}
Copiați

Prima funcție verifică dacă contractul de contor există pentru o anumită adresă, apoi apelează metoda getCount din instanță. A doua funcție: getMyCount este doar un capăt scurt pentru a trece msg.sender direct la funcția getCount.

Funcția increment este destul de asemănătoare, dar transmite expeditorul inițial al tranzacției la contractul Counter:

1function increment() public {
2 require (_counters[msg.sender] != Counter(0));
3 Counter(_counters[msg.sender]).increment(msg.sender);
4 }
Copiați

Reține că, dacă este apelat de mai multe ori, contorul nostru ar putea fi victima unui flux excesiv. Trebuie să utilizezi SafeMath Library(opens in a new tab) cât mai mult pentru a te proteja de acest caz posibil.

Pentru a implementa contractul nostru, va trebui să furnizezi atât codul CounterFactory, cât și Counter. Când implementezi, de exemplu, în Remix, va trebui să selectezi CounterFactory.

Aici este codul complet:

1pragma solidity 0.5.17;
2
3contract Counter {
4
5 uint256 private _count;
6 address private _owner;
7 address private _factory;
8
9
10 modifier onlyOwner(address caller) {
11 require(caller == _owner, "You're not the owner of the contract");
12 _;
13 }
14
15 modifier onlyFactory() {
16 require(msg.sender == _factory, "You need to use the factory");
17 _;
18 }
19
20 constructor(address owner) public {
21 _owner = owner;
22 _factory = msg.sender;
23 }
24
25 function getCount() public view returns (uint256) {
26 return _count;
27 }
28
29 function increment(address caller) public onlyFactory onlyOwner(caller) {
30 _count++;
31 }
32
33}
34
35contract CounterFactory {
36
37 mapping(address => Counter) _counters;
38
39 function createCounter() public {
40 require (_counters[msg.sender] == Counter(0));
41 _counters[msg.sender] = new Counter(msg.sender);
42 }
43
44 function increment() public {
45 require (_counters[msg.sender] != Counter(0));
46 Counter(_counters[msg.sender]).increment(msg.sender);
47 }
48
49 function getCount(address account) public view returns (uint256) {
50 require (_counters[account] != Counter(0));
51 return (_counters[account].getCount());
52 }
53
54 function getMyCount() public view returns (uint256) {
55 return (getCount(msg.sender));
56 }
57
58}
Afișează tot
Copiați

După compilare, în secțiunea Remix Deploy vei selecta fabrica ce va fi implementată:

Selectarea fabricii care va fi implementată în Remix

După aceea, poți să te joci cu fabrica de contract și să verifici cum se modifică valorile. Dacă dorești să apelezi contractul inteligent de la o adresă diferență va trebui să modifici adresa din „Selectare cont” din Remix.

Ultima modificare: @nhsz(opens in a new tab), 15 august 2023

A fost util acest tutorial?