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-Beispiel2contract SimpleStorage {3 uint storedData; // Zustandsvariable4 // ...5}1# Vyper-Beispiel2storedData: int128Wenn 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:
| Eigenschaft | Zustandsvariable | Beschreibung |
|---|---|---|
block.timestamp | uint256 | Aktueller Block-Epochen-Zeitstempel |
msg.sender | address | Absender 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
fkann nicht intern aufgerufen werden (d. h.f()funktioniert nicht, aberthis.f()funktioniert).
- Externe Funktionen sind Teil der Vertragsschnittstelle, was bedeutet, dass sie von 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 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-Beispiel2function 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, 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-Beispiel2function balanceOf(address _owner) public view returns (uint256 _balance) {3 return ownerPizzaCount[_owner];4}1dappName: public(string)23@view4@public5def readName() -> string:6 return dappNameWas als Änderung des Zustands gilt:
- Schreiben in Zustandsvariablen.
- Ausgeben von Ereignissen (Events) (opens in a new tab).
- Erstellen anderer Verträge (opens in a new tab).
- Verwendung von
selfdestruct. - Senden von Ether über Aufrufe (Calls).
- Aufrufen einer Funktion, die nicht als
viewoderpuremarkiert ist. - Verwendung von Low-Level-Aufrufen.
- 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-Beispiel2// 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-properties9 owner = msg.sender;10}Alle anzeigen1# Vyper-Beispiel23@external4def __init__(_beneficiary: address, _bidding_time: uint256):5 self.beneficiary = _beneficiary6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_timeEingebaute 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()– Soliditysend(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;23contract ExampleDapp {4 string dapp_name; // Zustandsvariable56 // Wird aufgerufen, wenn der Vertrag bereitgestellt wird, und initialisiert den Wert7 constructor() public {8 dapp_name = "My Example 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}Alle anzeigenEin 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#pragma3pragma solidity ^0.5.10;45// 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.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 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#constructors21 constructor(string memory initMessage) public {22 // Akzeptiert ein String-Argument `initMessage` und setzt den Wert23 // in die Speichervariable `message` des Vertrags).24 message = initMessage;25 }2627 // Eine öffentliche Funktion, die ein String-Argument akzeptiert28 // und die Speichervariable `message` aktualisiert.29 function update(string memory newMessage) public {30 message = newMessage;31 }32}Alle anzeigenToken
1pragma solidity ^0.5.10;23contract 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#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 (den Token-Kontostand) zu.11 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types12 mapping (address => uint) public balances;1314 // 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#events17 event Transfer(address from, address to, uint amount);1819 // 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-properties26 owner = msg.sender;27 }2829 // 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-exceptions3536 // Nur der Vertragseigentümer kann diese Funktion aufrufen37 require(msg.sender == owner, "You are not the owner.");3839 // Erzwingt eine maximale Menge an Token40 require(amount < 1e60, "Maximum issuance exceeded");4142 // Erhöht den Kontostand von `receiver` um `amount`43 balances[receiver] += amount;44 }4546 // 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 haben49 require(amount <= balances[msg.sender], "Insufficient balance.");5051 // Passt die Token-Kontostände 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}Alle 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 aus einem Ausdruck zuweisen, der zur Kompilierzeit 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 // Struct-Typen ermöglichen es Ihnen, Ihren eigenen Typ zu 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 Eigentümers38 mapping(uint256 => address) public pizzaToOwner;3940 // Mapping von der Adresse des Eigentümers zur Anzahl der besessenen Token41 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 mappt Eigentümer auf Operator-Genehmigungen47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // Interne Funktion, um eine zufällige Pizza aus einem String (Name) und DNA zu erstellen50 function _createPizza(string memory _name, uint256 _dna)51 // Das Schlüsselwort `internal` bedeutet, dass diese Funktion nur sichtbar ist52 // innerhalb dieses Vertrags und Verträgen, die von diesem Vertrag abgeleitet sind53 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters54 internal55 // `isUnique` ist ein Funktionsmodifikator, der überprü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 ruft die ID ab60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // Überprüft, ob der Pizza-Eigentümer derselbe wie der aktuelle Benutzer 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 // Mappt die Pizza auf den Eigentümer71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // 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 }8384 // Generiert zufällige DNA aus einem String (Name) und der Adresse des Eigentümers (Erstellers)85 function generateRandomDna(string memory _str, address _owner)86 public87 // Als `pure` markierte Funktionen versprechen, den Zustand weder zu lesen noch zu ändern88 // Mehr erfahren: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 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 }9899 // Gibt ein Array von Pizzen zurück, die vom Eigentümer gefunden wurden100 function getPizzasByOwner(address _owner)101 public102 // Als `view` markierte Funktionen versprechen, den Zustand nicht zu ä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 Eigentum an eine andere Adresse122 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.");127128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);130 pizzaToOwner[_pizzaId] = _to;131132 // Löst das im importierten IERC721-Vertrag definierte Ereignis aus133 emit Transfer(_from, _to, _pizzaId);134 _clearApproval(_to, _pizzaId);135 }136137 /* *138 * Überträgt sicher das Eigentum einer bestimmten Token-ID 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 144145146147148149150 function safeTransferFrom(address from, address to, uint256 pizzaId)151 public152 {153 // solium-disable-next-line arg-overflow154 this.safeTransferFrom(from, to, pizzaId, "");155 }156157 /* *158 * Überträgt sicher das Eigentum einer bestimmten Token-ID an eine andere Adresse159 * Wenn die Zieladresse ein Vertrag ist, muss sie `onERC721Received` implementieren,160 * was bei einer sicheren Übertragung aufgerufen wird, und den magischen Wert161 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` zurückgeben;162 * andernfalls wird die Übertragung rückgängig gemacht. */163 164165166167168169170 function safeTransferFrom(171 address from,172 address to,173 uint256 pizzaId,174 bytes memory _data175 ) public {176 this.transferFrom(from, to, pizzaId);177 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");178 }179180 /* *181 * Interne Funktion, um `onERC721Received` auf einer Zieladresse aufzurufen182 * Der Aufruf wird nicht ausgeführt, wenn die Zieladresse kein Vertrag ist */183 184185186187 function _checkOnERC721Received(188 address from,189 address to,190 uint256 pizzaId,191 bytes memory _data192 ) internal returns (bool) {193 if (!isContract(to)) {194 return true;195 }196197 bytes4 retval = IERC721Receiver(to).onERC721Received(198 msg.sender,199 from,200 pizzaId,201 _data202 );203 return (retval == _ERC721_RECEIVED);204 }205206 // Verbrennt eine Pizza - zerstört den Token vollständig207 // Der Funktionsmodifikator `external` bedeutet, dass diese Funktion208 // Teil der Vertragsschnittstelle ist und andere Verträge sie aufrufen können209 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.");213214 ownerPizzaCount[msg.sender] = SafeMath.sub(215 ownerPizzaCount[msg.sender],216 1217 );218 pizzaToOwner[_pizzaId] = address(0);219 }220221 // Gibt die Anzahl der Pizzen nach Adresse zurück222 function balanceOf(address _owner) public view returns (uint256 _balance) {223 return ownerPizzaCount[_owner];224 }225226 // Gibt den Eigentümer der Pizza zurück, die anhand der ID gefunden wurde227 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 }232233 // Genehmigt einer anderen Adresse, das Eigentum an der Pizza zu übertragen234 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 }239240 // Gibt die genehmigte Adresse für eine bestimmte Pizza zurück241 function getApproved(uint256 _pizzaId)242 public243 view244 returns (address operator)245 {246 require(_exists(_pizzaId), "Pizza does not exist.");247 return pizzaApprovals[_pizzaId];248 }249250 /* *251 * Private Funktion, um die aktuelle Genehmigung einer bestimmten Token-ID zu löschen252 * Wird rückgängig gemacht, wenn die angegebene Adresse nicht tatsächlich der Eigentümer des Tokens ist */253 254255256257 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 }264265 /* * Setzt oder hebt die Genehmigung eines bestimmten Operators auf266 * Ein Operator darf alle Token des Absenders in dessen Namen übertragen */267 268269270271 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 }276277 // Gibt an, ob ein Operator von einem bestimmten Eigentümer genehmigt ist278 function isApprovedForAll(address owner, address operator)279 public280 view281 returns (bool)282 {283 return operatorApprovals[owner][operator];284 }285286 // Übernimmt das Eigentum an der Pizza - nur für genehmigte Benutzer287 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 }292293 // Überprüft, ob die Pizza existiert294 function _exists(uint256 pizzaId) internal view returns (bool) {295 address owner = pizzaToOwner[pizzaId];296 return owner != address(0);297 }298299 // Überprüft, ob die Adresse der Eigentümer ist oder genehmigt ist, die Pizza zu übertragen300 function _isApprovedOrOwner(address spender, uint256 pizzaId)301 internal302 view303 returns (bool)304 {305 address owner = pizzaToOwner[pizzaId];306 // Deaktiviert die Solium-Prüfung wegen307 // https://github.com/duaraghav8/Solium/issues/175308 // solium-disable-next-line operator-whitespace309 return (spender == owner ||310 this.getApproved(pizzaId) == spender ||311 this.isApprovedForAll(owner, spender));312 }313314 // Überprüft, ob die Pizza einzigartig ist und noch nicht existiert315 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 == _dna322 ) {323 result = false;324 }325 }326 require(result, "Pizza with such name already exists.");327 _;328 }329330 // Gibt zurück, ob die Zieladresse ein Vertrag ist331 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/36603336 // für weitere Details darüber, wie dies funktioniert.337 // TODO Dies vor dem Serenity-Release noch einmal überprüfen, da dann alle Adressen338 // Verträge sein werden.339 // solium-disable-next-line security/no-inline-assembly340 assembly {341 size := extcodesize(account)342 }343 return size > 0;344 }345}Alle anzeigenWeiterführende Literatur
Sehen Sie sich die Dokumentation von Solidity und Vyper an, um einen vollständigeren Überblick über Smart Contracts zu erhalten:
Verwandte Themen
Verwandte Tutorials
- Verkleinerung von Verträgen zur Bekämpfung des Vertragslimit – Einige praktische Tipps zur Reduzierung der Größe Ihres Smart Contracts.
- Protokollieren von Daten aus Smart Contracts mit Ereignissen – Eine Einführung in Smart-Contract-Ereignisse und wie Sie diese zur Protokollierung von Daten verwenden können.
- Interaktion mit anderen Verträgen aus Solidity – Wie man einen Smart Contract aus einem bestehenden Vertrag bereitstellt und mit ihm interagiert.