Ethereum Smart Contract Tutorial: Lerne Solidity

Ethereum Smart Contract Tutorial Step 1: Solidity installieren
Du möchtest ein Smart Contract entwickeln, aber du weißt nicht wo du beginnen sollst? Mit unserem Ethereum Smart Contract Tutorial lernst du Schritt für Schritt wie du einen Smart Contract zusammen baust. Wir zeigen dir, wie du Solidity installierst, aus welchen Bestandteile ein Smart Contract besteht und wie du ihn modifizieren kannst.
Bevor wir unser Smart Contract programmieren können, müssen wir zunächst Solidity installieren. Jedoch ist schon das installieren etwas komplizierter, da die meisten für Linux und nicht für Microsoft gemacht wurden. Wir zeigen dir, wie du Solidity auf deinem Computer mit Windows Betriebssystem installieren kannst.

Bevor wir anfangen können musst du folgende Tools herunterladen:

Wenn du alles erfolgreich installiert hast, brauchen wir noch eine Erweiterung für Visual Studio, um Solidity ausführen zu können.
Den download dafür findest du hier

Damit wir nun loslegen können, musst du einen leeren Ordner namens Truffel auf deinem Desktop anlegen. Gehe dann in Visual Studio und öffne über File(Datei) -> Open Folder(Ordner öffnen) diesen Ordner. Anschließend musst du eine Test-Environment(Umgebung) herunterladen, auf dem wir dann den Smart Contract testen können.
Hierfür gib folgenden Befehl in das Terminal ein: npm install truffle -g
Ethereum Smart Contract Tutorial
Es gibt uns die nötigen Tools, um unseren Smart Contract entwickeln zu können. Zudem stellt es eine Testumgebung für unseren Smart Contract bereit.
Jetzt brauchen wir noch Ganache. Es ist ein lokale Blockchain für das Entwickeln und Testen von Solidity code.
Den Link dafür findest du hier.

Wir haben hier 10 Ethereum Accounts mit jeweils 100 Beispielhaften Ether die natürlich keinen realen Wert haben.
Ethereum Smart Contract Tutorial
Als letzten brauchen wir MetaMask als Browser Erweiterung. Damit verbinden wir den Browser mit der Blockchain und ermöglichen es, unseren Smart Contract auszuführen.
Optional: Das highlighten von Code hilft beim Programmieren, deshalb brauchen wir noch einen Texteditor. Er ist natürlich optional und du musst ihn nicht unbedingt heruntergeladen.
Den link dafür findest du hier

Nun haben wir alles wichtige installiert und können mit unserem Ethereum Smart Contract Tutorial weiter machen!

Ethereum Smart Contract Tutorial Step 2: Wichtige Datentypen für unseren Smart Contract

Nun zeigen wir dir die wichtigsten Datentypen, die du für deinen Smart Contract wissen solltest. Solidity ist eine statisch typisierte Sprache(damit ist gemeint, dass unsere Klassen alle static sein müssen), was bedeutet, dass der Typ jeder Variablen zur Kompilierungszeit angegeben werden muss.

Durch diese statischen Klassen können Zuweisungen nur einmal durchgeführt werden und dann nie wieder.
Bevor wir unseren Smart Contract erstellen können, erhältst du hier noch kurz eine kleine Einführung über die Datentypen von Solidity.

  • Hash: 256-Bit, 32-Byte-Daten-Chunk, indizierbar in Bytes und mit bitweisen Operationen betreibbar.
  • uint: 256-Bit Ganzzahl ohne Vorzeichen, die mit bitweisen und vorzeichenlosen arithmetischen Operationen arbeitet.
  • int: 256-Bit Ganzzahl mit Vorzeichen, die mit bitweisen und vorzeichenbehafteten (sprich Werte können negativ werden) arithmetischen Operationen arbeitet.
  • string32: Nullterminierter ASCII-String mit einer maximalen Länge von 32 Byte (256 Bit).
  • Adresse: Kontokennung, ähnlich einem 160-Bit-Hash-Typ.
  • bool: Zwei-Status-Werte, True/False.
  • Structs: physikalische Gruppierung von Variablen.

Mit diesen Datentypen ist es ganz einfach möglich, einen Smart Contract zu erstellen.

Ethereum Smart Contract Tutorial Step 3: Einen Smart Contract programmieren
Solidity ist eine Vertragsorientierte Programmiersprache für Ethereum. Im ersten Schritt zeige wir dir, wie du ganz einfach einen Solidity Smart Contract erstellen kannst. Dafür müssen wir Solidity am Anfang erstmal deutlich machen, dass wir überhaupt Solidity verwenden möchten und natürlich auch welche Version wir benötigen.

Smart Contract Klassen Erstellen

Dafür benutzten wir zu Beginn „pragma solidity“ und dann die Version die wir nutzen möchten.


pragma solidity ^0.4.0;

contract MyFirstContract {
      string name;
}

Danach bestimmen wir einen Vertrag vom Typ „Contract“. Nun müssen wir unserem Vertrag noch einen Namen geben. Hier kannst du dir jeden beliebigen Namen aussuchen. In unserem Fall heißt der Vertrag „MyFirstContract“.

Hierbei ist zu beachten, dass wir uns schon zu Beginn beim Anlegen von Variablen, Klassen, Methoden etc. an die richtige Notationen halten wollen. Das heißt, wir unterscheiden hierbei zwischen Camel Case und Pascal Case.

PascalCase bedeutet, dass derVariablen Namen mit einem Großbuchstaben beginnt. Das gilt aber nur für Klassennamen(z.B. Unserem Contract) und Methoden. Als Beispiel können wir unseren Vertrag MyFirstContract nehmen, wobei jedes neue Wort mit einem Großbuchstaben anfängt.

Beim camelCase beginnt hingegen jeder Name mit einem kleinen Buchstaben. Dieser wird jedoch nur bei Namen für Variablen (also zB. uint) und Argumenten von Methoden verwendet.

Benenne dein Smart Contract

Jetzt müssen wir bestimmen, was alles in unseren Smart Contract hineinkommt. Als Erstes legen wir ein Feld (sprich Variable) vom Typ „string“ für den Namen des Vertrags an.


pragma solidity ^0.4.0;

contract MyFirstContract {

     string name;
}

Datentypen festlegen

Du kannst diese Variable noch auf Private stellen. Dadurch wird gewährleistet, dass niemand von außen Zugriff auf dieses Feld hat. Das wird jedoch nicht wie bei Java am Anfang des Feldes gesetzt, sondern zwischen dem Datentyp und dem Namen des Feldes. Das sieht dann wie folgt aus:


pragma solidity ^0.4.0;

contract MyFirstContract {

     string private _name;
}

Des Weiteren brauchen wir für unseren Smart Contract ein Alter. Dafür benutzten wir „uint private _age“. Der Syntax sieht dann wie folgt aus:


pragma solidity ^0.4.0;

contract MyFirstContract {

     string private _name;

     uint private _age;
}

Erstelle eine Set und Get Funktion

Weil nun alle Felder auf privat gestellt sind, haben sie noch keine richtige Funktion. Deshalb erstellen wir nun eine set und get Funktion für „_name“ und „_age“. Dabei werden unsere beiden Felder nun zu einer Eigenschaft. Das heißt, wenn wir im späteren Verlauf von Eigenschaften reden, sprechen wir über Felder mit entweder einer set oder einer get- Funktion (oder natürlichen mit beidem). Aber was erreichen wir nun damit? Nun, mit Hilfe einer get-Funktionen können wir von außen auf unsere Variable zugreifen und zum Beispiel auf unserem Bildschirm ausgeben lassen. Jedoch bezieht sich das nur auf das Ausgeben und nicht auf die Zuweisungen. Dafür brauchen wir nun die set-Funktion. Über diese können wir einen Zugriff auf unsere Eigenschaften gewährleisten.

Nutzung der Set und Get Funktion

Über gewisse Plausibilitätsprüfungen können wir nun unzulässige Werte vorher abfangen. Zum Beispiel darf unsere Eigenschaft „Age“ nicht kleiner als 0 sein oder unser String „Name“ muss mindestens x Zeichen enthalten. Das können wir wie in JavaSkript erstellen. Dafür geben wir in die Konsole einfach „function“ ein. Danach erscheint das Keyword „set“ gefolgt von unserer Eigenschaft die wir verändern wolle, in unserem Fall also „Name“. Danach müssen wir wie bei unserer Methode, in runden Klammern einen Parameter deklarieren. Dieser eingegebenen Wert (string) wird dann von der Konsole gespeichert. In unserem Fall legen wir wieder eine Variable namens „newName“ vom gleichen Typ wie bei „_name“ an. Dieser wird innerhalb unserer set-Funktion dann unserer privaten Variable zugewiesen.

Das sieht dann wie folgt aus:


pragma solidity ^0.4.0;

contract MyFirstContract {

     string private _name;
     uint private _age;

     function setName(string newName) {
         _name = newName;
     }
}

Also alles was wir in die Konsole eingeben, wird über die Funktion „setName“, den Namen unseres Vertrags verändern.

Damit wir nun den Namen auf dem Bildschirm ausgeben können, schreiben wir für diesen noch eine get-Funktion. Das funktioniert wie mit der set-Funktion. Nur schreiben wir ein „get“ gefolgt von „Name“.

Der einzige Unterschied hierbei ist, dass wir keine Zuweisung haben, sondern lediglich ein Return, da wir ja nur den Wert angezeigt bekommen wollen.


pragma solidity ^0.4.0;

contract MyFirstContract {

     string private _name;
     uint private _age;

     function setName(string newName) {
         _name = newName;
     }

    function getName() returns (string) {
         return _name;
    }
}

Das Ganze machen wir jetzt noch für die Variable _age. Das sollte wie folgt aussehen:


pragma solidity ^0.4.0;

contract MyFirstContract {

     string private _name;
     uint private _age;

     function setName(string newName) {
         _name = newName;
     }

    function getName() returns (string) {
         return _name;
    }

     function setAge(unit newAge) {
         _age= newAge;
     }

    function getAge() returns (unit) {
         return _age;
    }
}

Erstelle einen Plausibilitätscheck

Zum Schluss können wir zu den beiden Set-Funktionen noch eine Plausibilitätsprüfungen hinzufügen. Für das Alter sagen wir naiver weise einfach, dass der Wert nicht kleiner 0 sein darf. Beim Namen wollen wir eine Eingabe mit mindestens einem Zeichen und dass dieser ungleich null sein soll.

Nun haben wir unsere zwei Methoden und können ganz einfach testen ob unser einfacher Smart Contract funktioniert. Dafür müssen wir einfach auf „Create“ drücken und wenn wir alles richtig gemacht haben können wir sowohl den Namen als auch das Alter eingeben. Wichtig dabei ist, das du bei String-Eingabe Anführungszeichen setzt.
Du hast nun deinen ersten sehr einfachen Smart Contract in Solidity erstellt.

Ethereum Smart Contract Tutorial Step 4: Smart Contract Vererbung
Nun haben wir einen einfachen Smart Contract mit ein paar Get und Set Funktionen erstellt. Nun können wir unseren einfachen Vertrag durch Vererbung erweitern. Dadurch erreichen wir eine allgemeine Erweiterung der Funktionalitäten von einem Vertrag zum nächsten.

Solidity Vererbung

Wir wollen nun von unserem ersten Vertrag „MyFirstContract“ vererben. Dadurch wird dieser zur sogenannten Oberklasse. Alle Klassen bzw. Verträge, die von diesem erben, werden automatisch zu dessen Unterklasse. Dabei erben die Unterklassen alle Methoden, Eigenschaften und Felder von der Oberklasse, ohne das diese neu angelegt werden müssen.
Wir müssen dadurch in unserem eigenen Vertrag keine weiteren Funktionen definieren, sondern können ganz einfach auf Funktionen der Oberklassen zugreifen.

Basierend auf unserem einfachen Smart Contract „MyFirstContract“ erstellen wir nun in Solidity einen neuen Vertrag namens „Bank“. Bank ist somit eine Unterklasse von „MyFirstContract“. Damit nun unseren „MyFirstContract“-Vertrag von „Bank“ die Funktionen erben kann, brauchen wir das Keyword „is“. Dieses wird dann einfach zwischen der Oberklasse und unserer Unterklasse eingefügt.
Das sieht dann wie folgt aus:


pragma solidity ^0.4.0;

contract MyFirstContract is Bank {

}

Erstelle einen Bankaccount

Nun müssen wir noch einen Smart Contract vom Typ „contract“ anlegen. Dieser funktioniert wie unser Bankaccount. Unser Bankaccount hat je nach Höhe der Geldeinzahlung ein bestimmten Wert, eine Möglichkeit Einzahlungen zu tätigen und das Geld wieder abzuheben.

Zunächst erstellen wir den Smart Contract „Bank“ mit einem unbestimmten Wert. Für diesen unbestimmten Wert legen wir ein neues privates Feld vom Typ „uint“ an und nennen diesen „_value“. Diesen Datentyp benutzen wir, da wir nur positive Werte wollen und es keinen Sinn machen würde, einen negativen Betrag einzahlen zu wollen. Solche Fälle können auch mit Hilfe einer Plausibilitätsprüfung abgefangen werden.


pragma solidity ^0.4.0;

contract Bank {

      uint private _value;
}

Erstellen einer Einzahlungsfunktion

Danach brauchen wir eine Funktion, mit der wir Geld auf das Konto einzahlen können. Die Funktion bekommt nun von außen (d.h. zum Beispiel durch eine Eingabe von der Konsole) einen Parameter vom Typ „unit“, welchen wir mit „amount“ deklarieren. Dabei passiert folgendes: Wenn man nun Geld einzahlen möchte, bekommt die Funktion „Deposit“ von außen einen bestimmten Wert zugewiesen. Innerhalb dieser Funktion führen wir nun folgende Berechnung aus.


pragma solidity ^0.4.0;

contract Bank {

uint private _value;

     function deposit(unit amount) {

     _value += amount;
     }
}

Der Wert des Bank Account ist dabei die Summe aller Einzahlungen die wir getätigt haben, also die Werte die „amount“ unserer Funktion weitergibt + unser aktuelles Bankguthaben. Deshalb verwenden wir „value+=amount;“.

Erstelle eine Abhebefunktion

Jetzt müssen wir noch in der Lage sein, Geld wieder abzuheben. Dafür schreiben wir eine „Withdraw“-Funktion.


pragma solidity ^0.4.0;

contract Bank {

      uint private _value;
 
      function deposit(unit amount) {

         _value += amount; 
      }

      function withdraw(unit amount) {

         _value -= amount; 
      }
}

Funktionieren tut diese Funktion eigentlich genau so wie unsere „Deposit“-Funktion. Nur ziehen wir innerhalb der Funktion den ausbezahlten Betrag von unserem Konto ab.

Der Wert des Accounts wird hierbei um den Wert „amount“ reduziert.

Erstellen einer Salden Funktion

Nun brauchen wir noch eine Funktion, um unseren derzeitigen Kontostand abfragen zu können. Dafür erstellen wir die Funktion „Balance“ die uns einen Integer-Wert zurückgeben soll. Hierbei benutzen wir nicht den Datentyp „uint“, da wir mit unserem Guthaben natürlich auch ins Negative gehen können.

Erstellt wird diese Funktion wie folgt: Zuerst schreiben wir das Schlüsselwort „function“, da es sich ja um eine Funktion handelt. Anschließend geben wir der Funktion einen Namen, in unserem Fall „Balance“. Direkt danach kommen 2 leere runde Klammern. Hätten wir noch Parameter, welche die Funktion von außen bekommen würde (siehen Funktion „Deposit“ oder „Withdraw“), müssten wir diese innerhalb der runden Klammern definieren. Als letztes kommt die Rückgabe der Funktion, welche mit dem Schlüsselwort „returns“ erfolgt anschließend der Datentyp der zurückgegeben werden soll.
Innerhalb der Funktion geben wir einfach den in unsere obigen Funktionen berechneten Wert „value“ zurück.


 pragma solidity ^0.4.0;

 contract Bank {
      uint private _value;
 
      function deposit(unit amount) {
         _value += amount; 
      }
     function withdraw(unit amount) {
        _value -= amount; 
     }
}

Die Funktion soll uns hierbei den aktuellen Wert unseres Bankkontos anzeigen.

Erstellen einer Prüfwertfunktion

Damit niemand Geld abhebt, das er nicht besitzt, müssen wir zum Schluss noch eine Funktion erstellen, die genau das überprüft. Dafür schreiben wir eine Funktion „CheckValue“ die uns einen „Boolean“ zurückgeben soll. Dieser Datentyp hat zwei Zustände, true oder false.
Aufgebaut ist die Funktion genauso wie unsere „Balance“- Funktion, nur kriegen wir diesmal einen Boolean zurück.


pragma solidity ^0.4.0;

contract Bank {

      uint private _value;
 
      function deposit(unit amount) {

         _value += amount; 
      }

      function withdraw(unit amount) {

         _value -= amount; 
      }

      function balance() returns(unit) {

         return _value;
      }

      function checkValue(uint amount) returns(bool) {

         return _value >= amount;
      }
}

Die Funktion soll überprüfen, ob der Betrag der abgehoben wird größer ist als der Wert des Bank Accounts.

Erstellen einer Plausibilitätsprüfung

Jetzt müssen wir noch unsere „Withdraw“- Funktion ändern, damit du nur dann Geld abheben kannst, wenn du auch genügend auf dem Konto hast. Wir erstellen hierfür eine Plausibilitätsprüfung. Diese funktionieren immer nach dem gleichen Prinzip. Da wir eine Funktion nur dann durchführen wollen, wenn alle Prüfungen erfolgreich waren, schreiben wir unsere Prüfung immer am Anfang einer Funktion. Mit Hilfe eines „if-Statements“ können wir unsere eben geschrieben Funktion „CheckValue“ in runden Klammern nach dem „if“ reinschreiben. Als Parameter bekommt diese Funktion nun den Betrag, den wir abheben wollen, also wird der Wert in „amount“ der Funktion übergeben. Ist die Prüfung in Ordnung, wird ein „true“ zurückgeliefert und wir arbeiten den Code innerhalb des „If-Statements“ ab. Alternativ würde auch „CheckValue(amount) == true“ funktionieren. Falls die Funktion jedoch „false“ liefert, würde die Berechnung nicht ausgeführt werden und das Bankkonto bleibt unberührt.

Diese sieht dann wie folgt aus:


pragma solidity ^0.4.0;

contract Bank {

      uint private _value;
 
      function deposit(unit amount) {

         _value += amount; 
      }

      function withdraw(unit amount) {

         if (checkValue(amount)) {

         _value -= amount;
         }
      }

      function balance() returns(unit) {

         return _value;
      }

      function checkValue(uint amount) returns(bool) {

        return _value >= amount;
      }
}

Unser Vertrag erbt von Bank

Damit ist unser virtueller Bank Account fertig. Wir können nun Geld ein- und auszahlen. Da unser Smart Contract „MyFirstContract“ von „Bank“ erbt, hat dieser nun auch die Funktionen „Deposit“, „Withdraw“ und „Balance“. Mit Solidity Vererbung kann nun ganz einfach eine Erweiterung der Funktionalitäten des Vertrags erreicht werden.

Ethereum Smart Contract Tutorial Step 5: Smart Contract Modifier
Unser Smart Contract ist jetzt fast fertig. Das einzige Problem das wir noch haben ist, dass jeder auf unseren Smart Contract zugreifen kann. In unserem Fall möchten wir das aber vermeiden. Um das zu ändern brauchen wir einen sogenannten Modifier. Dadurch können wir gewährleistet, dass nur derjenige der den Smart Contract erstellt hat, etwas ändern kann.

Solidity Modifier einfach erklärt

Wenn du einen Smart Contract erstellst, wird eine Nachricht an die Blockchain gesendet. Diese Nachricht erlaubt dir den Zugang zu deinem Contract. Damit nun niemand anderes außer der Ersteller des Smart Contracts etwas verändern kann, erstellen wir eine neue Variable vom Typ Adresse namens „_owner“.


pragma solidity ^0.4.0;

contract Bank {
      uint private _value;
      adresse private _owner;
 
}
Mit „address“ können wir einen 20-byte großen Wert speichern und Operationen wie zum Beispiel „==“ (Gleichheit) oder „>“ (größer als) durchführen. Dieser Datentyp besitzt darüber hinaus sogenannte „Member“. Das sind zusätzliche vorgeschrieben Methoden wie „send“ oder „balance“, die über einen Modifier aufgerufen werden können. Aber dazu kommen wir erst später.

Smart Contract Konstructor

Wir müssen jetzt noch im Konstruktor von Bank der privaten Variable „_owner“ die Nachricht beim Erstellen des Smart Contracts zuweisen. Konstruktoren funktionieren im Grunde wie normale Methoden bzw. Funktionen, jedoch haben sie ein paar signifikante Unterschiede. Zuerst einmal kommen wir zum Aufbau eines Konstruktors. Diese haben lediglich das Keyword „funtion“ vor dem eigentlichen Namen. Auch ist der Name nicht beliebig wählbar, denn dieser richtet sich immer nach dem Namen der Klasse bzw. in unserem Fall nach dem „contract“ (bei uns hier: „Bank“). Anders als bei Methoden hat der Konstruktor keine Rückgabewerte. Eine Klasse bzw. Contract kann so viele Konstruktoren haben, wie du möchtest, diese müssen sich jedoch mindestens in einem Parameter (die Variablen in den runden Klammern) unterscheiden. Diese Werte müssen beim Erstellen eines neuen Objektes bzw. Smart Contracts nach „new Contract ()“ in den Runden Klammern angegeben werden. (Contract c = new Contract( – hier -))

Das letzte und vielleicht wichtigste Merkmal eines Konstruktors ist, dass dieser nur einmal beim Erstellen eines Objektes bzw. Smart Contracts nach dem compilieren aufgerufen wird. Daher wird der Konstruktor in der Regel dafür verwendet, Startwerte (default-Werte) zu setzen und ungewünschte Eingaben mit Plausibilitätsprüfungen zu verhindern.
Dies sieht wie folgt aus:


pragma solidity ^0.4.0;

contract Bank {
      uint private _value;
      adresse private _owner;
 
       function Bank(uint amount){

              value = amount;
              owner = msg.sender;
       }
}

Erstelle einen Solidity Smart Contract Modifier

Um die private Variable „_owner“ jetzt benutzen zu können, müssen wir einen „modifier“ erstellen.


pragma solidity ^0.4.0;

contract Bank {

      uint private _value;
      adresse private _owner;

      function Bank(uint amount){

            value = amount;
            owner = msg.sender;
       }

       modifier _ownerFunc {

            require(owner == msg.sender);
            _;
      }
}

Dafür benutzten wir das Keyword „modifier“ und nennen unser Konstrukt „ownerFunc“. Jetzt legen wir noch die Anforderung mit „require“ fest, dass „_owner“ und die Nachricht des Erstellers gleich sein muss. Dabei wird lediglich die Adresse des Erstellers mit der des Senders verglichen. Ist diese Aussage „true“, wird der nachfolgende Code abgearbeitet. Bei „false“ passiert nichts. Danach setzten wir ein alleinstehendes „_;“ damit die Funktion immer als erstes ausgeführt wird. Dadurch wird ein Fehler angezeigt, wenn jemand der nicht der Ersteller des Smart Contract ist, etwas ändern möchte. Jetzt müssen wir nur noch unser modifier „ownerFunc“ zu jeder Funktion hinzufügen, wo wir nicht möchten, dass jemand außer der Ersteller etwas ändern kann.

Dabei fügen wir am Ende jeder betroffenen Methode nach den Parameterwerten unseren modifier „ownerFunc“ hinzu.


pragma solidity ^0.4.0;

contract Bank {
     uint private _value;
     adresse private _owner;
 
     modifier _ownerFunc {
            require(owner == msg.sender);
            _;
     }

     function deposit(unit amount) _ownerFunc {
             value += amount;
     }

     function withdraw(unit amount) _ownerFunc {
             if(checkValue(amount)) {
                value -= amount;
             }
     }
}

Nun kannst nur noch du als Ersteller des Smart Contracts Geld einzahlen und abheben.
Damit hast du deinen ersten einfachen und funktionierenden Smart Contract erstellt. Wir hoffen, dir hat unsere Ethereum Smart Contract Tutorial gefallen!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.