Mit anderen Contracts von Solidity aus interagieren
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;23contract Counter {45 uint256 private _count;6 address private _owner;7 address private _factory;8910 modifier onlyOwner(address caller) {11 require(caller == _owner, "Du bist nicht der Eigentümer des Vertrags");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "Du musst die Factory verwenden");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}Alles anzeigenBeachte, 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}56function 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;23contract Counter {45 uint256 private _count;6 address private _owner;7 address private _factory;8910 modifier onlyOwner(address caller) {11 require(caller == _owner, "Du bist nicht der Eigentümer des Vertrags");12 _;13 }1415 modifier onlyFactory() {16 require(msg.sender == _factory, "Du musst die Factory verwenden");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}Alles anzeigenNach dem Kompilieren wählst du im Bereitstellungsbereich von Remix die Factory aus, die bereitgestellt werden soll:
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
