Weiter zum Hauptinhalt

Mit anderen Contracts von Solidity aus interagieren

smart contracts
solidity
remix
deploying
composability
Fortgeschritten
jdourlens
5. April 2020
4 Minuten Lesedauer

In den vorherigen Tutorials haben wir viel gelernt, wie man seinen ersten Smart Contract bereitstellt und ihm einige Funktionen hinzufügt, wie Zugriffskontrolle mit Modifikatoren (opens in a new tab) oder Fehlerbehandlung in Solidity (opens in a new tab). In diesem Tutorial lernen wir, wie man einen Smart Contract von einem bestehenden Contract aus bereitstellt und mit ihm interagiert.

Wir erstellen einen Contract, der es jedem ermöglicht, seinen eigenen Counter-Smart-Contract zu haben. Dafür erstellen wir eine Factory, die CounterFactory heißen wird. Hier ist zunächst der Code unseres ursprünglichen Counter-Smart-Contracts:

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, "Du bist nicht der Eigentümer des Vertrags");
12 _;
13 }
14
15 modifier onlyFactory() {
16 require(msg.sender == _factory, "Du musst die Factory verwenden");
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}
Alles anzeigen

Beachte, dass wir den Contract-Code geringfügig geändert haben, um die Adresse der Factory und die Adresse des Contract-Eigentümers zu speichern. Wenn du einen Contract-Code von einem anderen Contract aus aufrufst, verweist msg.sender auf die Adresse unserer Contract-Factory. Dies ist ein sehr wichtiger Punkt, den man verstehen sollte, da die Verwendung eines Contracts zur Interaktion mit anderen Contracts gängige Praxis ist. Daher solltest du in komplexen Fällen darauf achten, wer der Absender ist.

Dafür haben wir auch einen onlyFactory-Modifikator hinzugefügt, der sicherstellt, dass die zustandsändernde Funktion nur von der Factory aufgerufen werden kann, die den ursprünglichen Aufrufer als Parameter übergibt.

Innerhalb unserer neuen CounterFactory, die alle anderen Counter verwalten wird, fügen wir ein Mapping hinzu, das einem Eigentümer die Adresse seines Counter-Contracts zuordnet:

1mapping(address => Counter) _counters;

In Ethereum sind Mappings das Äquivalent zu Objekten in Javascript; sie ermöglichen es, einen Schlüssel vom Typ A einem Wert vom Typ B zuzuordnen. In diesem Fall ordnen wir die Adresse eines Eigentümers der Instanz seines Counters zu.

Das Instanziieren eines neuen Counter für jemanden sieht wie folgt aus:

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

Zuerst prüfen wir, ob die Person bereits einen Counter besitzt. Wenn die Person keinen Counter besitzt, instanziieren wir einen neuen, indem wir ihre Adresse an den Counter-Konstruktor übergeben und die neu erstellte Instanz dem Mapping zuweisen.

Um den Zählerstand eines bestimmten Counter abzurufen, sieht es wie folgt aus:

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}

Die erste Funktion prüft, ob der Counter-Contract für eine bestimmte Adresse existiert, und ruft dann die getCount-Methode von der Instanz auf. Die zweite Funktion, getMyCount, ist nur eine Abkürzung, um msg.sender direkt an die getCount-Funktion zu übergeben.

Die increment-Funktion ist recht ähnlich, übergibt aber den ursprünglichen Transaktionssender an den Counter-Contract:

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

Beachte, dass unser Counter bei zu häufigen Aufrufen Opfer eines Überlaufs werden könnte. Du solltest die SafeMath-Bibliothek (opens in a new tab) so oft wie möglich verwenden, um dich vor diesem möglichen Fall zu schützen.

Um unseren Contract bereitzustellen, musst du sowohl den Code der CounterFactory als auch den des Counter angeben. Bei der Bereitstellung in Remix musst du zum Beispiel CounterFactory auswählen.

Hier ist der vollständige Code:

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, "Du bist nicht der Eigentümer des Vertrags");
12 _;
13 }
14
15 modifier onlyFactory() {
16 require(msg.sender == _factory, "Du musst die Factory verwenden");
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}
Alles anzeigen

Nach dem Kompilieren wählst du im Bereitstellungsbereich von Remix die Factory aus, die bereitgestellt werden soll:

Auswahl der in Remix bereitzustellenden Factory

Danach kannst du mit deiner Contract Factory interagieren und die Wertänderung überprüfen. Wenn du den Smart Contract von einer anderen Adresse aus aufrufen möchtest, musst du die Adresse in der Kontoauswahl von Remix ändern.

Seite zuletzt aktualisiert: 15. August 2023

War dieses Tutorial hilfreich?