Anatomie von Smart Contracts
Seite zuletzt aktualisiert: 14. Februar 2026
Ein Smart Contract ist ein Programm, das auf einer Adresse auf Ethereum läuft. Ein solcher Vertrag besteht aus Daten und Funktionen, die nach dem Erhalt einer Transaktion ausgeführt werden können. Hier ein Überblick darüber, was einen Smart Contract ausmacht.
Voraussetzungen
Stellen Sie sicher, dass Sie sich zuerst über Smart Contracts informiert haben. Die Informationen in diesem Dokument sind für Personen gedacht, die bereits mit Programmiersprachen wie JavaScript oder Python vertraut sind.
Daten
Alle Vertragsdaten müssen einem Ort zugewiesen werden: entweder storage oder memory. Speicher in einem Smart Contract zu ändern ist ein kostenintensiver Prozess. Daher sollten Sie sich überlegen, wo Ihre Daten gespeichert werden sollen.
Speicher
Gleichbleibende Daten werden als Speicher oder Storage bezeichnet und über Zustandsvariablen dargestellt. Solche Daten werden dauerhaft auf der Blockchain gespeichert. Sie müssen den Typ deklarieren, damit der Contract beim Kompilieren verfolgen kann, wie viel Speicherplatz er auf der Blockchain benötigt.
1// Solidity-Beispiel2contract SimpleStorage {3 uint storedData; // Zustandsvariable4 // ...5}1# Vyper example2storedData: int128Wenn Sie bereits Erfahrung im Programmieren in objektorientierten Sprachen haben, werden Sie wahrscheinlich mit den meisten Typen vertraut sein. Allerdings sollte Ihnen address neu sein, wenn Sie neu in der Ethereum-Entwicklung sind.
Ein address-Typ kann eine Ethereum-Adresse aufnehmen, was 20 Bytes oder 160 Bits entspricht. Die Ausgabe erfolgt in hexadezimaler Schreibweise mit einem führenden 0x.
Andere Typen umfassen:
- boolesch
- Ganzzahl
- Festkommazahlen
- Byte-Arrays mit fester Größe
- Byte-Arrays mit dynamischer Größe
- rationale und ganzzahlige Literale
- Zeichenfolgenliterale
- hexadezimale Literale
- Enums
Weitere Erklärungen finden Sie in folgender Dokumentation:
Speicher
Werte, die nur für die Lebensdauer der Ausführung einer Vertragsfunktion gespeichert werden, werden als Memory Variables (Speichervariablen) bezeichnet. Da diese nicht dauerhaft auf der Blockchain gespeichert werden, sind sie wesentlich preiswerter.
Erfahren Sie in den Solidity-Dokumentenopens in a new tab mehr darüber, wie die EVM Daten speichert (Storage, Memory und der Stack).
Umgebungsvariablen
Zusätzlich zu den Variablen, die Sie in Ihrem Vertrag definieren, gibt es einige spezielle globale Variablen. Sie werden in erster Linie verwendet, um Informationen über die Blockchain oder aktuelle Transaktion bereitzustellen.
Beispiele:
| Eigenschaft | Statusvariable | Beschreibung |
|---|---|---|
block.timestamp | uint256 | Aktueller Zeitstempel der Block-Epoche |
msg.sender | address | Absender der Nachricht (aktueller Aufruf) |
Funktionen
Vereinfacht gesagt können Funktionen als Antwort auf eingehende Transaktionen Informationen erhalten oder festlegen.
Es gibt zwei Arten von Functionsaufrufen:
internal– diese erzeugen keinen EVM-Aufruf- Auf interne Funktionen und Zustandsvariablen kann nur intern zugegriffen werden (d. h. aus dem aktuellen Vertrag oder von ihm abgeleiteten Verträgen)
external– diese erzeugen einen EVM-Aufruf- Externe Funktionen sind Teil der Vertragsschnittstelle. Das bedeutet, dass sie aus anderen Verträgen und über Transaktionen aufgerufen werden können. Eine externe Funktion
fkann nicht intern aufgerufen werden (d. h.f()funktioniert nicht, aberthis.f()funktioniert).
- Externe Funktionen sind Teil der Vertragsschnittstelle. Das bedeutet, dass sie aus anderen Verträgen und über Transaktionen aufgerufen werden können. Eine externe Funktion
Sie können auch public oder private sein
public-Funktionen können intern aus dem Vertrag heraus oder extern über Nachrichten aufgerufen werdenprivate-Funktionen sind nur für den Vertrag sichtbar, in dem sie definiert sind, und nicht in abgeleiteten Verträgen
Sowohl Funktionen als auch Statusvariablen können öffentlich oder privat gemacht werden.
Hier ist eine Funktion zum Aktualisieren einer Zustandsvariable für einen Smart Contract:
1// Solidity example2function update_name(string value) public {3 dapp_name = value;4}- Der Parameter
valuevom Typstringwird an die Funktion übergeben:update_name - Sie ist als
publicdeklariert, was bedeutet, dass jeder darauf zugreifen kann - Sie ist nicht als
viewdeklariert, sodass sie den Vertragszustand ändern kann
View-Funktionen
Diese Funktionen verpflichten sich, den Zustand der Vertragsdaten nicht zu ändern. Gängige Beispiele sind "Getter"-Funktionen, mit denen Sie z. B. den Kontostand eines Benutzers abfragen können.
1// Solidity example2function balanceOf(address _owner) public view returns (uint256 _balance) {3 return ownerPizzaCount[_owner];4}1dappName: public(string)23@view4@public5def readName() -> string:6 return dappNameFolgende Vorgänge werden als Modifikation des Zustands angesehen:
- In Zustandsvariablen schreiben
- Auslösen von Ereignissenopens in a new tab.
- Erstellen anderer Verträgeopens in a new tab.
- Verwenden von
selfdestruct. - Ether über Aufrufe senden
- Aufrufen von Funktionen, die nicht als
viewoderpuremarkiert sind. - Low-Level-Aufrufe verwenden
- Inline-Assembly verwenden, die bestimmte Opcodes enthält
Konstruktor-Funktionen
constructor-Funktionen werden nur einmal ausgeführt, wenn der Vertrag zum ersten Mal bereitgestellt wird. Ähnlich wie der constructor in vielen klassenbasierten Programmiersprachen initialisieren diese Funktionen oft Zustandsvariablen mit ihren angegebenen Werten.
1// Solidity-Beispiel2// Initialisiert die Vertragsdaten und setzt den `owner`3// auf die Adresse des Vertragserstellers.4constructor() public {5 // Alle Smart Contracts sind auf externe Transaktionen angewiesen, um ihre Funktionen auszulösen.6 // `msg` ist eine globale Variable, die relevante Daten über die jeweilige Transaktion enthält,7 // wie z. B. die Adresse des Absenders und den in der Transaktion enthaltenen ETH-Wert.8 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties9 owner = msg.sender;10}Alles anzeigen1# Vyper example23@external4def __init__(_beneficiary: address, _bidding_time: uint256):5 self.beneficiary = _beneficiary6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_timeIntegrierte Funktionen
Zusätzlich zu den Variablen, die Sie in Ihrem Vertrag definieren, gibt es einige spezielle integrierte Funktionen. Das offensichtlichste Beispiel ist:
address.send()– Soliditysend(address)– Vyper
Diese erlauben es Smart Contracts, ETH an andere Konten zu senden.
Schreiben von Funktionen
Ihre Funktion benötigt folgende Elemente:
- Parametervariable und -typ (wenn Parameter akzeptiert werden)
- interne/externe Deklaration
- Deklaration von pure/view/payable
- Gibt den Typ zurück (wenn er einen Wert zurückgibt)
1pragma solidity >=0.4.0 <=0.6.0;23contract ExampleDapp {4 string dapp_name; // Zustandsvariable56 // Wird aufgerufen, wenn der Vertrag bereitgestellt wird, und initialisiert den Wert7 constructor() public {8 dapp_name = "Meine Beispiel-Dapp";9 }1011 // Get-Funktion12 function read_name() public view returns(string) {13 return dapp_name;14 }1516 // Set-Funktion17 function update_name(string value) public {18 dapp_name = value;19 }20}Alles anzeigenEin vollständiger Smart Contract könnte so aussehen. Hier liefert die constructor-Funktion einen Anfangswert für die Variable dapp_name.
Ereignisse und Protokolle
Ereignisse ermöglichen es Ihrem Smart Contract, mit Ihrem Frontend oder anderen abonnierenden Anwendungen zu kommunizieren. Sobald eine Transaktion validiert und einem Block hinzugefügt wurde, können Smart Contracts Ereignisse auslösen und Informationen protokollieren, die das Frontend dann verarbeiten und nutzen kann.
Kommentierte Beispiele
Das sind einige Beispiele in Solidity. Wenn Sie mit dem Code experimentieren möchten, können Sie in Remixopens in a new tab mit ihnen interagieren.
Hallo Welt
1// Gibt die Version von Solidity an und verwendet die semantische Versionierung.2// Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma3pragma solidity ^0.5.10;45// Definiert einen Vertrag mit dem Namen `HelloWorld`.6// Ein Vertrag ist eine Sammlung von Funktionen und Daten (seinem Zustand).7// Nach der Bereitstellung befindet sich ein Vertrag an einer bestimmten Adresse auf der Ethereum-Blockchain.8// Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 // Deklariert eine Zustandsvariable `message` vom Typ `string`.12 // Zustandsvariablen sind Variablen, deren Werte dauerhaft im Vertragsspeicher gespeichert werden.13 // Das Schlüsselwort `public` macht Variablen von außerhalb eines Vertrags zugänglich14 // und erstellt eine Funktion, die andere Verträge oder Clients aufrufen können, um auf den Wert zuzugreifen.15 string public message;1617 // Ähnlich wie in vielen klassenbasierten objektorientierten Sprachen ist ein Konstruktor18 // eine spezielle Funktion, die nur bei der Erstellung des Vertrags ausgeführt wird.19 // Konstruktoren werden verwendet, um die Daten des Vertrags zu initialisieren.20 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) public {22 // Akzeptiert ein Zeichenfolgen-Argument `initMessage` und setzt den Wert23 // in die `message`-Speichervariable des Vertrags).24 message = initMessage;25 }2627 // Eine öffentliche Funktion, die ein Zeichenfolgen-Argument akzeptiert28 // und die `message`-Speichervariable aktualisiert.29 function update(string memory newMessage) public {30 message = newMessage;31 }32}Alles anzeigenToken
1pragma solidity ^0.5.10;23contract Token {4 // Eine `address` ist mit einer E-Mail-Adresse vergleichbar – sie wird verwendet, um ein Konto auf Ethereum zu identifizieren.5 // Adressen können einen Smart Contract oder externe (Benutzer-)Konten darstellen.6 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/types.html#address7 address public owner;89 // Ein `mapping` ist im Wesentlichen eine Hash-Tabellen-Datenstruktur.10 // Dieses `mapping` weist einer Adresse (dem Token-Inhaber) eine vorzeichenlose Ganzzahl (das Token-Guthaben) zu.11 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types12 mapping (address => uint) public balances;1314 // Ereignisse ermöglichen die Protokollierung von Aktivitäten auf der Blockchain.15 // Ethereum-Clients können auf Ereignisse lauschen, um auf Änderungen des Vertragszustands zu reagieren.16 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events17 event Transfer(address from, address to, uint amount);1819 // Initialisiert die Vertragsdaten und setzt den `owner`20 // auf die Adresse des Vertragserstellers.21 constructor() public {22 // Alle Smart Contracts sind auf externe Transaktionen angewiesen, um ihre Funktionen auszulösen.23 // `msg` ist eine globale Variable, die relevante Daten über die jeweilige Transaktion enthält,24 // wie z. B. die Adresse des Absenders und den in der Transaktion enthaltenen ETH-Wert.25 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties26 owner = msg.sender;27 }2829 // Erstellt eine Menge neuer Tokens und sendet sie an eine Adresse.30 function mint(address receiver, uint amount) public {31 // `require` ist eine Kontrollstruktur, die zur Durchsetzung bestimmter Bedingungen verwendet wird.32 // Wenn eine `require`-Anweisung zu `false` ausgewertet wird, wird eine Ausnahme ausgelöst,33 // die alle während des aktuellen Aufrufs am Zustand vorgenommenen Änderungen rückgängig macht.34 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions3536 // Nur der Vertragsinhaber kann diese Funktion aufrufen37 require(msg.sender == owner, "Sie sind nicht der Inhaber.");3839 // Erzwingt eine maximale Menge an Tokens40 require(amount < 1e60, "Maximale Emission überschritten");4142 // Erhöht das Guthaben von `receiver` um `amount`43 balances[receiver] += amount;44 }4546 // Sendet eine Menge bestehender Tokens von einem beliebigen Aufrufer an eine Adresse.47 function transfer(address receiver, uint amount) public {48 // Der Absender muss über genügend Tokens verfügen, um sie zu senden49 require(amount <= balances[msg.sender], "Ungenügendes Guthaben.");5051 // Passt die Token-Guthaben der beiden Adressen an52 balances[msg.sender] -= amount;53 balances[receiver] += amount;5455 // Löst das zuvor definierte Ereignis aus56 emit Transfer(msg.sender, receiver, amount);57 }58}Alles anzeigenEinzigartiger digitaler Vermögenswert
1pragma solidity ^0.5.10;23// Importiert Symbole aus anderen Dateien in den aktuellen Vertrag.4// In diesem Fall eine Reihe von Hilfsverträgen von OpenZeppelin.5// Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files67import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";1112// Das Schlüsselwort `is` wird verwendet, um Funktionen und Schlüsselwörter von externen Verträgen zu erben.13// In diesem Fall erbt `CryptoPizza` von den Verträgen `IERC721` und `ERC165`.14// Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance15contract CryptoPizza is IERC721, ERC165 {16 // Verwendet die SafeMath-Bibliothek von OpenZeppelin, um arithmetische Operationen sicher durchzuführen.17 // Mehr erfahren: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath18 using SafeMath for uint256;1920 // Konstante Zustandsvariablen in Solidity sind ähnlich wie in anderen Sprachen,21 // aber Sie müssen sie aus einem Ausdruck zuweisen, der zur Kompilierungszeit konstant ist.22 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables23 uint256 constant dnaDigits = 10;24 uint256 constant dnaModulus = 10 ** dnaDigits;25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;2627 // Mit Struct-Typen können Sie Ihren eigenen Typ definieren28 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs29 struct Pizza {30 string name;31 uint256 dna;32 }3334 // Erstellt ein leeres Array von Pizza-Structs35 Pizza[] public pizzas;3637 // Mapping von der Pizza-ID zur Adresse ihres Besitzers38 mapping(uint256 => address) public pizzaToOwner;3940 // Mapping von der Adresse des Besitzers zur Anzahl der besessenen Tokens41 mapping(address => uint256) public ownerPizzaCount;4243 // Mapping von der Token-ID zur genehmigten Adresse44 mapping(uint256 => address) pizzaApprovals;4546 // Sie können Mappings verschachteln, dieses Beispiel bildet Besitzer auf Betreibergenehmigungen ab47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // Interne Funktion zum Erstellen einer zufälligen Pizza aus einer Zeichenfolge (Name) und DNA50 function _createPizza(string memory _name, uint256 _dna)51 // Das Schlüsselwort `internal` bedeutet, dass diese Funktion nur52 // innerhalb dieses Vertrags und von Verträgen, die von diesem Vertrag abgeleitet sind, sichtbar ist53 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters54 internal55 // `isUnique` ist ein Funktionsmodifikator, der prüft, ob die Pizza bereits existiert56 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers57 isUnique(_name, _dna)58 {59 // Fügt Pizza zum Array von Pizzen hinzu und erhält die ID60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // Überprüft, ob der Pizzabesitzer mit dem aktuellen Benutzer identisch ist63 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions6465 // beachten Sie, dass address(0) die Null-Adresse ist,66 // was anzeigt, dass pizza[id] noch keinem bestimmten Benutzer zugewiesen ist.6768 assert(pizzaToOwner[id] == address(0));6970 // Ordnet die Pizza dem Besitzer zu71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // Erstellt eine zufällige Pizza aus einer Zeichenfolge (Name)79 function createRandomPizza(string memory _name) public {80 uint256 randDna = generateRandomDna(_name, msg.sender);81 _createPizza(_name, randDna);82 }8384 // Erzeugt eine zufällige DNA aus einer Zeichenfolge (Name) und der Adresse des Besitzers (Erstellers)85 function generateRandomDna(string memory _str, address _owner)86 public87 // Funktionen, die als `pure` markiert sind, versprechen, den Zustand weder zu lesen noch zu verändern88 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 returns (uint256)91 {92 // Erzeugt eine zufällige uint aus einer Zeichenfolge (Name) + Adresse (Besitzer)93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +94 uint256(_owner);95 rand = rand % dnaModulus;96 return rand;97 }9899 // Gibt ein Array von Pizzen zurück, die nach Besitzer gefunden wurden100 function getPizzasByOwner(address _owner)101 public102 // Funktionen, die als `view` markiert sind, versprechen, den Zustand nicht zu verändern103 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions104 view105 returns (uint256[] memory)106 {107 // Verwendet den Speicherort `memory`, um Werte nur für den108 // Lebenszyklus dieses Funktionsaufrufs zu speichern.109 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);111 uint256 counter = 0;112 for (uint256 i = 0; i < pizzas.length; i++) {113 if (pizzaToOwner[i] == _owner) {114 result[counter] = i;115 counter++;116 }117 }118 return result;119 }120121 // Überträgt Pizza und Besitz an eine andere Adresse122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {123 require(_from != address(0) && _to != address(0), "Ungültige Adresse.");124 require(_exists(_pizzaId), "Pizza existiert nicht.");125 require(_from != _to, "Kann nicht an dieselbe Adresse übertragen werden.");126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Adresse ist nicht genehmigt.");127128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);130 pizzaToOwner[_pizzaId] = _to;131132 // Löst ein Ereignis aus, das im importierten IERC721-Vertrag definiert ist133 emit Transfer(_from, _to, _pizzaId);134 _clearApproval(_to, _pizzaId);135 }136137 /**138 * Überträgt den Besitz einer bestimmten Token-ID sicher an eine andere Adresse139 * Wenn die Zieladresse ein Vertrag ist, muss sie `onERC721Received` implementieren,140 * was bei einer sicheren Übertragung aufgerufen wird, und den magischen Wert141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` zurückgeben;142 * andernfalls wird die Übertragung rückgängig gemacht.143 */144 function safeTransferFrom(address from, address to, uint256 pizzaId)145 public146 {147 // solium-disable-next-line arg-overflow148 this.safeTransferFrom(from, to, pizzaId, "");149 }150151 /**152 * Überträgt den Besitz einer bestimmten Token-ID sicher an eine andere Adresse153 * Wenn die Zieladresse ein Vertrag ist, muss sie `onERC721Received` implementieren,154 * was bei einer sicheren Übertragung aufgerufen wird, und den magischen Wert155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` zurückgeben;156 * andernfalls wird die Übertragung rückgängig gemacht.157 */158 function safeTransferFrom(159 address from,160 address to,161 uint256 pizzaId,162 bytes memory _data163 ) public {164 this.transferFrom(from, to, pizzaId);165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Muss onERC721Received implementieren.");166 }167168 /**169 * Interne Funktion zum Aufrufen von `onERC721Received` auf einer Zieladresse170 * Der Aufruf wird nicht ausgeführt, wenn die Zieladresse kein Vertrag ist171 */172 function _checkOnERC721Received(173 address from,174 address to,175 uint256 pizzaId,176 bytes memory _data177 ) internal returns (bool) {178 if (!isContract(to)) {179 return true;180 }181182 bytes4 retval = IERC721Receiver(to).onERC721Received(183 msg.sender,184 from,185 pizzaId,186 _data187 );188 return (retval == _ERC721_RECEIVED);189 }190191 // Verbrennt eine Pizza – zerstört den Token vollständig192 // Der Funktionsmodifikator `external` bedeutet, dass diese Funktion193 // Teil der Vertragsschnittstelle ist und andere Verträge sie aufrufen können194 function burn(uint256 _pizzaId) external {195 require(msg.sender != address(0), "Ungültige Adresse.");196 require(_exists(_pizzaId), "Pizza existiert nicht.");197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Adresse ist nicht genehmigt.");198199 ownerPizzaCount[msg.sender] = SafeMath.sub(200 ownerPizzaCount[msg.sender],201 1202 );203 pizzaToOwner[_pizzaId] = address(0);204 }205206 // Gibt die Anzahl der Pizzen nach Adresse zurück207 function balanceOf(address _owner) public view returns (uint256 _balance) {208 return ownerPizzaCount[_owner];209 }210211 // Gibt den Besitzer der Pizza zurück, die nach ID gefunden wurde212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {213 address owner = pizzaToOwner[_pizzaId];214 require(owner != address(0), "Ungültige Pizza-ID.");215 return owner;216 }217218 // Genehmigt eine andere Adresse, um den Besitz der Pizza zu übertragen219 function approve(address _to, uint256 _pizzaId) public {220 require(msg.sender == pizzaToOwner[_pizzaId], "Muss der Pizzabesitzer sein.");221 pizzaApprovals[_pizzaId] = _to;222 emit Approval(msg.sender, _to, _pizzaId);223 }224225 // Gibt die genehmigte Adresse für eine bestimmte Pizza zurück226 function getApproved(uint256 _pizzaId)227 public228 view229 returns (address operator)230 {231 require(_exists(_pizzaId), "Pizza existiert nicht.");232 return pizzaApprovals[_pizzaId];233 }234235 /**236 * Private Funktion, um die aktuelle Genehmigung für eine bestimmte Token-ID zu löschen237 * Macht die Aktion rückgängig, wenn die angegebene Adresse nicht tatsächlich der Besitzer des Tokens ist238 */239 function _clearApproval(address owner, uint256 _pizzaId) private {240 require(pizzaToOwner[_pizzaId] == owner, "Muss Pizzabesitzer sein.");241 require(_exists(_pizzaId), "Pizza existiert nicht.");242 if (pizzaApprovals[_pizzaId] != address(0)) {243 pizzaApprovals[_pizzaId] = address(0);244 }245 }246247 /*248 * Setzt oder hebt die Genehmigung eines bestimmten Betreibers auf249 * Ein Betreiber darf alle Tokens des Absenders in dessen Namen übertragen250 */251 function setApprovalForAll(address to, bool approved) public {252 require(to != msg.sender, "Eigene Adresse kann nicht genehmigt werden");253 operatorApprovals[msg.sender][to] = approved;254 emit ApprovalForAll(msg.sender, to, approved);255 }256257 // Gibt an, ob ein Betreiber von einem bestimmten Besitzer genehmigt ist258 function isApprovedForAll(address owner, address operator)259 public260 view261 returns (bool)262 {263 return operatorApprovals[owner][operator];264 }265266 // Übernimmt den Besitz der Pizza – nur für genehmigte Benutzer267 function takeOwnership(uint256 _pizzaId) public {268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Adresse ist nicht genehmigt.");269 address owner = this.ownerOf(_pizzaId);270 this.transferFrom(owner, msg.sender, _pizzaId);271 }272273 // Prüft, ob Pizza existiert274 function _exists(uint256 pizzaId) internal view returns (bool) {275 address owner = pizzaToOwner[pizzaId];276 return owner != address(0);277 }278279 // Prüft, ob die Adresse der Besitzer ist oder für die Übertragung der Pizza genehmigt ist280 function _isApprovedOrOwner(address spender, uint256 pizzaId)281 internal282 view283 returns (bool)284 {285 address owner = pizzaToOwner[pizzaId];286 // Deaktiviere die Solium-Prüfung wegen287 // https://github.com/duaraghav8/Solium/issues/175288 // solium-disable-next-line operator-whitespace289 return (spender == owner ||290 this.getApproved(pizzaId) == spender ||291 this.isApprovedForAll(owner, spender));292 }293294 // Prüfen, ob die Pizza einzigartig ist und noch nicht existiert295 modifier isUnique(string memory _name, uint256 _dna) {296 bool result = true;297 for (uint256 i = 0; i < pizzas.length; i++) {298 if (299 keccak256(abi.encodePacked(pizzas[i].name)) ==300 keccak256(abi.encodePacked(_name)) &&301 pizzas[i].dna == _dna302 ) {303 result = false;304 }305 }306 require(result, "Pizza mit diesem Namen existiert bereits.");307 _;308 }309310 // Gibt zurück, ob die Zieladresse ein Vertrag ist311 function isContract(address account) internal view returns (bool) {312 uint256 size;313 // Derzeit gibt es keine bessere Möglichkeit zu prüfen, ob es einen Vertrag an einer Adresse gibt,314 // als die Größe des Codes an dieser Adresse zu prüfen.315 // Siehe https://ethereum.stackexchange.com/a/14016/36603316 // für weitere Details zur Funktionsweise.317 // TODO Dies vor der Serenity-Version erneut prüfen, da dann alle Adressen318 // Verträge sein werden.319 // solium-disable-next-line security/no-inline-assembly320 assembly {321 size := extcodesize(account)322 }323 return size > 0;324 }325}Alles anzeigenWeiterführende Lektüre
Sehen Sie sich auch die Dokumentationen zu Solidity und Vyper an, um einen umfassenderen Überblick über Smart Contracts zu erhalten:
Verwandte Themen
Verwandte Tutorials
- Verkleinern von Verträgen, um das Vertraggrößenlimit zu bekämpfen – Einige praktische Tipps zur Reduzierung der Größe Ihres Smart Contracts.
- Protokollierung von Daten aus Smart Contracts mit Ereignissen – Eine Einführung in Smart-Contract-Ereignisse und wie Sie diese zur Datenprotokollierung verwenden können.
- Mit anderen Verträgen aus Solidity interagieren – Wie man einen Smart Contract aus einem bestehenden Vertrag bereitstellt und mit ihm interagiert.