Zum Hauptinhalt springen
Change page

Anatomie von Smart Contracts

Letzte Aktualisierung der Seite: 23. Februar 2026

Ein Smart Contract ist ein Programm, das unter einer Adresse auf Ethereum läuft. Sie bestehen aus Daten und Funktionen, die nach Erhalt einer Transaktion ausgeführt werden können. Hier ist ein Überblick darüber, woraus ein Smart Contract besteht.

Voraussetzungen

Stellen Sie sicher, dass Sie zuerst über Smart Contracts gelesen haben. Dieses Dokument setzt voraus, dass Sie bereits mit Programmiersprachen wie JavaScript oder Python vertraut sind.

Daten

Alle Vertragsdaten müssen einem Speicherort zugewiesen werden: entweder storage (Speicher) oder memory (Arbeitsspeicher). Es ist teuer, den Speicher in einem Smart Contract zu ändern, daher müssen Sie sich überlegen, wo Ihre Daten abgelegt werden sollen.

Storage

Persistente Daten werden als Storage bezeichnet und durch Zustandsvariablen (State Variables) repräsentiert. Diese Werte werden dauerhaft auf der Blockchain gespeichert. Sie müssen den Typ deklarieren, damit der Vertrag beim Kompilieren nachverfolgen kann, wie viel Speicherplatz er auf der Blockchain benötigt.

1// Solidity-Beispiel
2contract SimpleStorage {
3 uint storedData; // Zustandsvariable
4 // ...
5}
1# Vyper-Beispiel
2storedData: int128

Wenn Sie bereits in objektorientierten Sprachen programmiert haben, werden Ihnen die meisten Typen wahrscheinlich vertraut sein. address sollte jedoch neu für Sie sein, wenn Sie neu in der Ethereum-Entwicklung sind.

Ein address-Typ kann eine Ethereum-Adresse aufnehmen, was 20 Bytes oder 160 Bits entspricht. Sie wird in hexadezimaler Schreibweise mit einem führenden 0x zurückgegeben.

Weitere Typen sind:

  • Boolean (Wahrheitswerte)
  • Integer (Ganzzahlen)
  • Fixed Point Numbers (Festkommazahlen)
  • Fixed-size Byte Arrays (Byte-Arrays fester Größe)
  • Dynamically sized Byte Arrays (Byte-Arrays dynamischer Größe)
  • Rational and Integer Literals (Rationale und ganzzahlige Literale)
  • String Literals (Zeichenketten-Literale)
  • Hexadecimal Literals (Hexadezimale Literale)
  • Enums (Aufzählungstypen)

Für weitere Erklärungen werfen Sie einen Blick in die Dokumentation:

Memory

Werte, die nur für die Lebensdauer der Ausführung einer Vertragsfunktion gespeichert werden, nennt man Memory-Variablen. Da diese nicht dauerhaft auf der Blockchain gespeichert werden, sind sie in der Nutzung viel günstiger.

Erfahren Sie mehr darüber, wie die EVM Daten speichert (Storage, Memory und der Stack) in der Solidity-Dokumentation (opens in a new tab).

Umgebungsvariablen

Zusätzlich zu den Variablen, die Sie in Ihrem Vertrag definieren, gibt es einige spezielle globale Variablen. Sie werden hauptsächlich verwendet, um Informationen über die Blockchain oder die aktuelle Transaktion bereitzustellen.

Beispiele:

EigenschaftZustandsvariableBeschreibung
block.timestampuint256Aktueller Block-Epochen-Zeitstempel
msg.senderaddressAbsender der Nachricht (aktueller Aufruf)

Funktionen

Vereinfacht gesagt können Funktionen als Reaktion auf eingehende Transaktionen Informationen abrufen oder festlegen.

Es gibt zwei Arten von Funktionsaufrufen:

  • internal – diese erzeugen keinen EVM-Aufruf
    • Auf interne Funktionen und Zustandsvariablen kann nur intern zugegriffen werden (d. h. aus dem aktuellen Vertrag oder aus Verträgen, die davon abgeleitet sind).
  • external – diese erzeugen einen EVM-Aufruf
    • Externe Funktionen sind Teil der Vertragsschnittstelle, was bedeutet, dass sie von anderen Verträgen und über Transaktionen aufgerufen werden können. Eine externe Funktion f kann nicht intern aufgerufen werden (d. h. f() funktioniert nicht, aber this.f() funktioniert).

Sie können auch public oder private sein:

  • public-Funktionen können intern aus dem Vertrag heraus oder extern über Nachrichten aufgerufen werden.
  • private-Funktionen sind nur für den Vertrag sichtbar, in dem sie definiert sind, und nicht in abgeleiteten Verträgen.

Sowohl Funktionen als auch Zustandsvariablen können öffentlich (public) oder privat (private) gemacht werden.

Hier ist eine Funktion zum Aktualisieren einer Zustandsvariablen in einem Vertrag:

1// Solidity-Beispiel
2function update_name(string value) public {
3 dapp_name = value;
4}
  • Der Parameter value vom Typ string wird an die Funktion übergeben: update_name
  • Sie ist als public deklariert, was bedeutet, dass jeder darauf zugreifen kann.
  • Sie ist nicht als view deklariert, kann also den Vertragszustand ändern.

View-Funktionen

Diese Funktionen versprechen, den Zustand der Vertragsdaten nicht zu verändern. Häufige Beispiele sind "Getter"-Funktionen – Sie könnten diese beispielsweise verwenden, um das Guthaben eines Benutzers abzurufen.

1// Solidity-Beispiel
2function balanceOf(address _owner) public view returns (uint256 _balance) {
3 return ownerPizzaCount[_owner];
4}
1dappName: public(string)
2
3@view
4@public
5def readName() -> string:
6 return dappName

Was als Änderung des Zustands gilt:

  1. Schreiben in Zustandsvariablen.
  2. Ausgeben von Ereignissen (Events) (opens in a new tab).
  3. Erstellen anderer Verträge (opens in a new tab).
  4. Verwendung von selfdestruct.
  5. Senden von Ether über Aufrufe (Calls).
  6. Aufrufen einer Funktion, die nicht als view oder pure markiert ist.
  7. Verwendung von Low-Level-Aufrufen.
  8. Verwendung von Inline-Assembly, das bestimmte Opcodes enthält.

Konstruktor-Funktionen

constructor-Funktionen werden nur einmal ausgeführt, wenn der Vertrag zum ersten Mal bereitgestellt wird. Wie der constructor in vielen klassenbasierten Programmiersprachen initialisieren diese Funktionen oft Zustandsvariablen auf ihre angegebenen Werte.

1// Solidity-Beispiel
2// Initialisiert die Daten des Vertrags 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 zur jeweiligen Transaktion enthält,
7 // wie 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-properties
9 owner = msg.sender;
10}
Alle anzeigen
1# Vyper-Beispiel
2
3@external
4def __init__(_beneficiary: address, _bidding_time: uint256):
5 self.beneficiary = _beneficiary
6 self.auctionStart = block.timestamp
7 self.auctionEnd = self.auctionStart + _bidding_time

Eingebaute Funktionen

Zusätzlich zu den Variablen und Funktionen, die Sie in Ihrem Vertrag definieren, gibt es einige spezielle eingebaute Funktionen. Das offensichtlichste Beispiel ist:

  • address.send() – Solidity
  • send(address) – Vyper

Diese ermöglichen es Verträgen, ETH an andere Konten zu senden.

Funktionen schreiben

Ihre Funktion benötigt:

  • Parametervariable und Typ (wenn sie Parameter akzeptiert)
  • Deklaration von internal/external
  • Deklaration von pure/view/payable
  • Rückgabetyp (wenn sie einen Wert zurückgibt)
1pragma solidity >=0.4.0 <=0.6.0;
2
3contract ExampleDapp {
4 string dapp_name; // Zustandsvariable
5
6 // Wird aufgerufen, wenn der Vertrag bereitgestellt wird, und initialisiert den Wert
7 constructor() public {
8 dapp_name = "My Example dapp";
9 }
10
11 // Get-Funktion
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // Set-Funktion
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
Alle anzeigen

Ein vollständiger Vertrag könnte in etwa so aussehen. Hier liefert die constructor-Funktion einen Anfangswert für die Variable dapp_name.

Ereignisse und Protokolle

Ereignisse (Events) 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 ausgeben und Informationen protokollieren, die das Frontend dann verarbeiten und nutzen kann.

Kommentierte Beispiele

Dies sind einige in Solidity geschriebene Beispiele. Wenn Sie mit dem Code spielen möchten, können Sie in Remix (opens in a new tab) mit ihnen interagieren.

Hello World

1// Gibt die Solidity-Version unter Verwendung semantischer Versionierung an.
2// Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// Definiert einen Vertrag namens `HelloWorld`.
6// Ein Vertrag ist eine Sammlung von Funktionen und Daten (seinem Zustand).
7// Sobald er bereitgestellt ist, 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.html
9contract HelloWorld {
10
11 // 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änglich
14 // und erstellt eine Funktion, die andere Verträge oder Clients aufrufen können, um auf den Wert zuzugreifen.
15 string public message;
16
17 // Ähnlich wie in vielen klassenbasierten objektorientierten Sprachen ist ein Konstruktor
18 // eine spezielle Funktion, die nur bei der Vertragserstellung 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#constructors
21 constructor(string memory initMessage) public {
22 // Akzeptiert ein String-Argument `initMessage` und setzt den Wert
23 // in die Speichervariable `message` des Vertrags).
24 message = initMessage;
25 }
26
27 // Eine öffentliche Funktion, die ein String-Argument akzeptiert
28 // und die Speichervariable `message` aktualisiert.
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
Alle anzeigen

Token

1pragma solidity ^0.5.10;
2
3contract Token {
4 // Eine `address` ist vergleichbar mit einer E-Mail-Adresse - sie wird verwendet, um ein Konto auf Ethereum zu identifizieren.
5 // Adressen können einen Smart Contract oder externe (Benutzer-)Konten repräsentieren.
6 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // Ein `mapping` ist im Wesentlichen eine Hash-Tabellen-Datenstruktur.
10 // Dieses `mapping` weist einer Adresse (dem Token-Inhaber) eine vorzeichenlose Ganzzahl (den Token-Kontostand) zu.
11 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // Ereignisse (Events) 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#events
17 event Transfer(address from, address to, uint amount);
18
19 // Initialisiert die Daten des Vertrags 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 zur jeweiligen Transaktion enthält,
24 // wie 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-properties
26 owner = msg.sender;
27 }
28
29 // Erstellt eine Menge neuer Token und sendet sie an eine Adresse.
30 function mint(address receiver, uint amount) public {
31 // `require` ist eine Kontrollstruktur, die verwendet wird, um bestimmte Bedingungen zu erzwingen.
32 // Wenn eine `require`-Anweisung als `false` ausgewertet wird, wird eine Ausnahme ausgelöst,
33 // die alle Änderungen rückgängig macht, die während des aktuellen Aufrufs am Zustand vorgenommen wurden.
34 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
35
36 // Nur der Vertragseigentümer kann diese Funktion aufrufen
37 require(msg.sender == owner, "You are not the owner.");
38
39 // Erzwingt eine maximale Menge an Token
40 require(amount < 1e60, "Maximum issuance exceeded");
41
42 // Erhöht den Kontostand von `receiver` um `amount`
43 balances[receiver] += amount;
44 }
45
46 // Sendet eine Menge existierender Token von einem beliebigen Aufrufer an eine Adresse.
47 function transfer(address receiver, uint amount) public {
48 // Der Absender muss genügend Token zum Senden haben
49 require(amount <= balances[msg.sender], "Insufficient balance.");
50
51 // Passt die Token-Kontostände der beiden Adressen an
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // Löst das zuvor definierte Ereignis aus
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
Alle anzeigen

Einzigartiger digitaler Vermögenswert

1pragma solidity ^0.5.10;
2
3// 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-files
6
7import "../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";
11
12// 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#inheritance
15contract 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#SafeMath
18 using SafeMath for uint256;
19
20 // Konstante Zustandsvariablen in Solidity sind ähnlich wie in anderen Sprachen,
21 // aber Sie müssen aus einem Ausdruck zuweisen, der zur Kompilierzeit konstant ist.
22 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables
23 uint256 constant dnaDigits = 10;
24 uint256 constant dnaModulus = 10 ** dnaDigits;
25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
26
27 // Struct-Typen ermöglichen es Ihnen, Ihren eigenen Typ zu definieren
28 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // Erstellt ein leeres Array von Pizza-Structs
35 Pizza[] public pizzas;
36
37 // Mapping von der Pizza-ID zur Adresse ihres Eigentümers
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // Mapping von der Adresse des Eigentümers zur Anzahl der besessenen Token
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // Mapping von der Token-ID zur genehmigten Adresse
44 mapping(uint256 => address) pizzaApprovals;
45
46 // Sie können Mappings verschachteln, dieses Beispiel mappt Eigentümer auf Operator-Genehmigungen
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // Interne Funktion, um eine zufällige Pizza aus einem String (Name) und DNA zu erstellen
50 function _createPizza(string memory _name, uint256 _dna)
51 // Das Schlüsselwort `internal` bedeutet, dass diese Funktion nur sichtbar ist
52 // innerhalb dieses Vertrags und Verträgen, die von diesem Vertrag abgeleitet sind
53 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
54 internal
55 // `isUnique` ist ein Funktionsmodifikator, der überprüft, ob die Pizza bereits existiert
56 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // Fügt Pizza zum Array von Pizzen hinzu und ruft die ID ab
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // Überprüft, ob der Pizza-Eigentümer derselbe wie der aktuelle Benutzer ist
63 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64
65 // beachten Sie, dass address(0) die Null-Adresse ist,
66 // was anzeigt, dass pizza[id] noch keinem bestimmten Benutzer zugewiesen ist.
67
68 assert(pizzaToOwner[id] == address(0));
69
70 // Mappt die Pizza auf den Eigentümer
71 pizzaToOwner[id] = msg.sender;
72 ownerPizzaCount[msg.sender] = SafeMath.add(
73 ownerPizzaCount[msg.sender],
74 1
75 );
76 }
77
78 // Erstellt eine zufällige Pizza aus einem String (Name)
79 function createRandomPizza(string memory _name) public {
80 uint256 randDna = generateRandomDna(_name, msg.sender);
81 _createPizza(_name, randDna);
82 }
83
84 // Generiert zufällige DNA aus einem String (Name) und der Adresse des Eigentümers (Erstellers)
85 function generateRandomDna(string memory _str, address _owner)
86 public
87 // Als `pure` markierte Funktionen versprechen, den Zustand weder zu lesen noch zu ändern
88 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
89 pure
90 returns (uint256)
91 {
92 // Generiert einen zufälligen uint aus String (Name) + Adresse (Eigentümer)
93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
94 uint256(_owner);
95 rand = rand % dnaModulus;
96 return rand;
97 }
98
99 // Gibt ein Array von Pizzen zurück, die vom Eigentümer gefunden wurden
100 function getPizzasByOwner(address _owner)
101 public
102 // Als `view` markierte Funktionen versprechen, den Zustand nicht zu ändern
103 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
104 view
105 returns (uint256[] memory)
106 {
107 // Verwendet den Speicherort `memory`, um Werte nur für den
108 // 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-stack
110 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 }
120
121 // Überträgt Pizza und Eigentum an eine andere Adresse
122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
123 require(_from != address(0) && _to != address(0), "Invalid address.");
124 require(_exists(_pizzaId), "Pizza does not exist.");
125 require(_from != _to, "Cannot transfer to the same address.");
126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
127
128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
130 pizzaToOwner[_pizzaId] = _to;
131
132 // Löst das im importierten IERC721-Vertrag definierte Ereignis aus
133 emit Transfer(_from, _to, _pizzaId);
134 _clearApproval(_to, _pizzaId);
135 }
136
137 /* *
138 * Überträgt sicher das Eigentum einer bestimmten Token-ID an eine andere Adresse
139 * Wenn die Zieladresse ein Vertrag ist, muss sie `onERC721Received` implementieren,
140 * was bei einer sicheren Übertragung aufgerufen wird, und den magischen Wert
141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` zurückgeben;
142 * andernfalls wird die Übertragung rückgängig gemacht. */
143
144
145
146
147
148
149
150 function safeTransferFrom(address from, address to, uint256 pizzaId)
151 public
152 {
153 // solium-disable-next-line arg-overflow
154 this.safeTransferFrom(from, to, pizzaId, "");
155 }
156
157 /* *
158 * Überträgt sicher das Eigentum einer bestimmten Token-ID an eine andere Adresse
159 * Wenn die Zieladresse ein Vertrag ist, muss sie `onERC721Received` implementieren,
160 * was bei einer sicheren Übertragung aufgerufen wird, und den magischen Wert
161 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` zurückgeben;
162 * andernfalls wird die Übertragung rückgängig gemacht. */
163
164
165
166
167
168
169
170 function safeTransferFrom(
171 address from,
172 address to,
173 uint256 pizzaId,
174 bytes memory _data
175 ) public {
176 this.transferFrom(from, to, pizzaId);
177 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");
178 }
179
180 /* *
181 * Interne Funktion, um `onERC721Received` auf einer Zieladresse aufzurufen
182 * Der Aufruf wird nicht ausgeführt, wenn die Zieladresse kein Vertrag ist */
183
184
185
186
187 function _checkOnERC721Received(
188 address from,
189 address to,
190 uint256 pizzaId,
191 bytes memory _data
192 ) internal returns (bool) {
193 if (!isContract(to)) {
194 return true;
195 }
196
197 bytes4 retval = IERC721Receiver(to).onERC721Received(
198 msg.sender,
199 from,
200 pizzaId,
201 _data
202 );
203 return (retval == _ERC721_RECEIVED);
204 }
205
206 // Verbrennt eine Pizza - zerstört den Token vollständig
207 // Der Funktionsmodifikator `external` bedeutet, dass diese Funktion
208 // Teil der Vertragsschnittstelle ist und andere Verträge sie aufrufen können
209 function burn(uint256 _pizzaId) external {
210 require(msg.sender != address(0), "Invalid address.");
211 require(_exists(_pizzaId), "Pizza does not exist.");
212 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
213
214 ownerPizzaCount[msg.sender] = SafeMath.sub(
215 ownerPizzaCount[msg.sender],
216 1
217 );
218 pizzaToOwner[_pizzaId] = address(0);
219 }
220
221 // Gibt die Anzahl der Pizzen nach Adresse zurück
222 function balanceOf(address _owner) public view returns (uint256 _balance) {
223 return ownerPizzaCount[_owner];
224 }
225
226 // Gibt den Eigentümer der Pizza zurück, die anhand der ID gefunden wurde
227 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
228 address owner = pizzaToOwner[_pizzaId];
229 require(owner != address(0), "Invalid Pizza ID.");
230 return owner;
231 }
232
233 // Genehmigt einer anderen Adresse, das Eigentum an der Pizza zu übertragen
234 function approve(address _to, uint256 _pizzaId) public {
235 require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner.");
236 pizzaApprovals[_pizzaId] = _to;
237 emit Approval(msg.sender, _to, _pizzaId);
238 }
239
240 // Gibt die genehmigte Adresse für eine bestimmte Pizza zurück
241 function getApproved(uint256 _pizzaId)
242 public
243 view
244 returns (address operator)
245 {
246 require(_exists(_pizzaId), "Pizza does not exist.");
247 return pizzaApprovals[_pizzaId];
248 }
249
250 /* *
251 * Private Funktion, um die aktuelle Genehmigung einer bestimmten Token-ID zu löschen
252 * Wird rückgängig gemacht, wenn die angegebene Adresse nicht tatsächlich der Eigentümer des Tokens ist */
253
254
255
256
257 function _clearApproval(address owner, uint256 _pizzaId) private {
258 require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner.");
259 require(_exists(_pizzaId), "Pizza does not exist.");
260 if (pizzaApprovals[_pizzaId] != address(0)) {
261 pizzaApprovals[_pizzaId] = address(0);
262 }
263 }
264
265 /* * Setzt oder hebt die Genehmigung eines bestimmten Operators auf
266 * Ein Operator darf alle Token des Absenders in dessen Namen übertragen */
267
268
269
270
271 function setApprovalForAll(address to, bool approved) public {
272 require(to != msg.sender, "Cannot approve own address");
273 operatorApprovals[msg.sender][to] = approved;
274 emit ApprovalForAll(msg.sender, to, approved);
275 }
276
277 // Gibt an, ob ein Operator von einem bestimmten Eigentümer genehmigt ist
278 function isApprovedForAll(address owner, address operator)
279 public
280 view
281 returns (bool)
282 {
283 return operatorApprovals[owner][operator];
284 }
285
286 // Übernimmt das Eigentum an der Pizza - nur für genehmigte Benutzer
287 function takeOwnership(uint256 _pizzaId) public {
288 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
289 address owner = this.ownerOf(_pizzaId);
290 this.transferFrom(owner, msg.sender, _pizzaId);
291 }
292
293 // Überprüft, ob die Pizza existiert
294 function _exists(uint256 pizzaId) internal view returns (bool) {
295 address owner = pizzaToOwner[pizzaId];
296 return owner != address(0);
297 }
298
299 // Überprüft, ob die Adresse der Eigentümer ist oder genehmigt ist, die Pizza zu übertragen
300 function _isApprovedOrOwner(address spender, uint256 pizzaId)
301 internal
302 view
303 returns (bool)
304 {
305 address owner = pizzaToOwner[pizzaId];
306 // Deaktiviert die Solium-Prüfung wegen
307 // https://github.com/duaraghav8/Solium/issues/175
308 // solium-disable-next-line operator-whitespace
309 return (spender == owner ||
310 this.getApproved(pizzaId) == spender ||
311 this.isApprovedForAll(owner, spender));
312 }
313
314 // Überprüft, ob die Pizza einzigartig ist und noch nicht existiert
315 modifier isUnique(string memory _name, uint256 _dna) {
316 bool result = true;
317 for (uint256 i = 0; i < pizzas.length; i++) {
318 if (
319 keccak256(abi.encodePacked(pizzas[i].name)) ==
320 keccak256(abi.encodePacked(_name)) &&
321 pizzas[i].dna == _dna
322 ) {
323 result = false;
324 }
325 }
326 require(result, "Pizza with such name already exists.");
327 _;
328 }
329
330 // Gibt zurück, ob die Zieladresse ein Vertrag ist
331 function isContract(address account) internal view returns (bool) {
332 uint256 size;
333 // Derzeit gibt es keinen besseren Weg, um zu überprüfen, ob sich an einer Adresse ein Vertrag befindet,
334 // als die Größe des Codes an dieser Adresse zu überprüfen.
335 // Siehe https://ethereum.stackexchange.com/a/14016/36603
336 // für weitere Details darüber, wie dies funktioniert.
337 // TODO Dies vor dem Serenity-Release noch einmal überprüfen, da dann alle Adressen
338 // Verträge sein werden.
339 // solium-disable-next-line security/no-inline-assembly
340 assembly {
341 size := extcodesize(account)
342 }
343 return size > 0;
344 }
345}
Alle anzeigen

Weiterführende Literatur

Sehen Sie sich die Dokumentation von Solidity und Vyper an, um einen vollständigeren Überblick über Smart Contracts zu erhalten:

War dieser Artikel hilfreich?