Commit 945752ea authored by Christoph Gross's avatar Christoph Gross 🤖

Initial Commit

parents
# Created by https://www.gitignore.io/api/soliditytruffle
# Edit at https://www.gitignore.io/?templates=soliditytruffle
### SolidityTruffle ###
# depedencies
node_modules
# testing
coverage
# production
build
build_webpack
#truffle
.tern-port
yarn.lock
package-lock.json
# End of https://www.gitignore.io/api/soliditytruffle
# Aufgabe 1: Einstieg
Wir verwenden für den Großteil der folgenden Truffle, eine Entwicklungsumgebung für Smart Contracts.
Wir haben Truffle bereits für euch vorinstalliert. Für den Einstieg verwenden wir nun ein Demoprojekt für Truffle namens "Metacoin"
1. Öffnet ein Terminal und führt den folgenden Befehlt aus um das Projekt zu initalisieren und herunterzuladen:
```
mkdir metacoin
cd metacoin
truffle unbox metacoin
```
Ihr solltet dann eine Ausgabe wie die folgenden bekommen:
```
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile contracts: truffle compile
Migrate contracts: truffle migrate
Test contracts: truffle test
```
## Projektstruktur von Truffle
Eure Ordnerstruktur sollte dann wie folgend aussehen:
```
.
├── contracts
│ ├── ConvertLib.sol
│ ├── MetaCoin.sol
│ └── Migrations.sol
├── migrations
│ ├── 1_initial_migration.js
│ └── 2_deploy_contracts.js
├── test
│ ├── TestMetacoin.sol
│ └── metacoin.js
├── truffle-config.js
└── truffle.js
```
### Contracts-Ordner
Das ist der Ordner, in welchem ihr all eure Smart Contracts speichern werdet.
Im Contracts-Ordner befindet sich auch die Datei `Migrations.sol`, welche eine spezielle Datei ist. Mehr dazu aber in einem später Abschnitt.
Beim Kompilieren des Projekts geht Truffle durch den Contracts-Ordner und kompiliert alle kompatible Dateien. Das meist verwendete Format für Smart Contracts ist aktuell Solidity für Ethereum. In Zukunft könnte sich das aber in Richtung Vyper oder SolidityX verändern, da beide per default sicherer sein sollen als Solidity.
### Migrations-Ordner
Was ist eine Truffle-Migration?
- Im Grunde ist es ein Skript, welches definiert, wie die Smart Contracts auf der Blockchain eingesetzt/verteilt werden. (Deployment)
Warum sind diese Migrationen notwendig?
- Mit der Komplexität des Projekts steigt zugleich auch die Schwierigkeit des Deployments auf der Blockchain.
Ein kleines Beispiel:
Wir haben die Smart Contracts A, B und C.
Der Smart Contract C beinhaltet eine Referenz auf den Smart Contract A und benötigt die Adresse des Smart Contracts B in seinem Konstruktor.
Bei diesem Beispiel müssen die Smart Contracts nicht nur sequenziell angwendet werden, sondern sie haben auch gegenseitige Querverweise. Zusammengefasst gesagt: Migrationen erlauben uns diesen Prozess zu automatisieren.
Eine Beispielmigration für das obige Beispiel könnte wie folgend aussehen:
```javascript
var One = artifacts.require("One");
var Two = artifacts.require("Two");
var Three = artifacts.require("Three");
module.exports = function(deployer) {
deployer.deploy(One).then(function() {
deployer.deploy(Two).then(function() {
deployer.deploy(Three, One.address);
})
});
};
```
Zusätzlich erlauben Migrationen weitere Dinge wie:
- Max Gas für Deployments festlegen
- Herkunftsadresse (`from address`) von Deployments verändern
- Librarys installieren/anwenden
- Aufrufen beliebiger Smart Contract Funktionen
Wie ihr vielleicht bereits gesehen habt, beinhaltet das MetaCoin-Projekt eine Datei namens `1_initial_migration.js`. Diese Datei verteilt den `Migrations.sol` Smart Contract auf der Blockchain.
Normalerweise muss diese Datei nicht geändert werden nachdem das Projekt einmal initialisiert wurde.
### Test-Ordner
Smart Contracts MÜSSEN getestet werden. Es geht schließlich um viel Geld und es gab bereits genügend Vorfälle bei denen Smart Contracts Lücken und Fehler aufwiesen.
Um diesen Prozess zu automatisieren liefert Truffle ein eingebautes Testframework mit. Es erlaubt Tests entweder in Solidity oder Javascript zu schreiben.
Schaut euch die Beispiele am besten etwas genauer an, da ihr in einer späteren Aufgabe auch noch Tests schreiben müsst.
Falls ihr Tests in Solidity schreibt, könnt ihr eure Smart Contracts mit der folgenden Zeile importieren:
`import "../contracts/MetaCoin.sol";`
Beim Schreiben von Tests in Javascript importiert ihr diese mit der `artifacts.require()` Hilfsfunktion:
`var MetaCoin = artifacts.require("./MetaCoin.sol");`
### Konfigurationsdatei
Die Konfigurationsdatei heißt entweder `truffle.js` oder `truffle-config.js`.
In der Konfigurationsdatei können verschiedene Dinge festgelegt und verändert werden:
- Umgebungsvariablen für Entwicklung, Testnetz und Produktion wie Netzwerkadressen, Netzwerk-IDs, Max Gas,...
- Kompilerversion und -parameter (für solc)
- Packetmanagment (für EthPM)
- Projektbeschreibung (Projektname, -autor)
## Ausführen des Codes
- Zum Kompilieren der Smart Contracts:
`truffle compile`
- Zum Durchführen der Migrationen:
`truffle migrate`
Es können aber auch spezifische Umgebungen angegeben werden:
`truffle migrate --network live`
Zum Rekompilieren und Migrieren aller Smart Contracts (nicht nur von Änderungen) kann folgender Befehl verwendet werden:
`truffle migrate --reset --compile-all`
- Zum Testen der Smart Contracts:
`truffle test`
Oder um spezifische Tests laufen zu lassen:
`truffle test ./path/to/TestFile.sol`
Testet alle drei Kommandos, wobei die Migration einen Fehler ausgeben sollte, da wir aktuell noch kein Ethereum Testnetz gestartet haben.
# Aufgabe 1: Einstieg
Wir verwenden für den Großteil der folgenden Truffle, eine Entwicklungsumgebung für Smart Contracts.
Wir haben Truffle bereits für euch vorinstalliert. Für den Einstieg verwenden wir nun ein Demoprojekt für Truffle namens "Metacoin"
1. Öffnet ein Terminal und führt den folgenden Befehlt aus um das Projekt zu initalisieren und herunterzuladen:
```
mkdir metacoin
cd metacoin
truffle unbox metacoin
```
Ihr solltet dann eine Ausgabe wie die folgenden bekommen:
```
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile contracts: truffle compile
Migrate contracts: truffle migrate
Test contracts: truffle test
```
## Projektstruktur von Truffle
Eure Ordnerstruktur sollte dann wie folgend aussehen:
```
.
├── contracts
│ ├── ConvertLib.sol
│ ├── MetaCoin.sol
│ └── Migrations.sol
├── migrations
│ ├── 1_initial_migration.js
│ └── 2_deploy_contracts.js
├── test
│ ├── TestMetacoin.sol
│ └── metacoin.js
├── truffle-config.js
└── truffle.js
```
### Contracts-Ordner
Das ist der Ordner, in welchem ihr all eure Smart Contracts speichern werdet.
Im Contracts-Ordner befindet sich auch die Datei `Migrations.sol`, welche eine spezielle Datei ist. Mehr dazu aber in einem später Abschnitt.
Beim Kompilieren des Projekts geht Truffle durch den Contracts-Ordner und kompiliert alle kompatible Dateien. Das meist verwendete Format für Smart Contracts ist aktuell Solidity für Ethereum. In Zukunft könnte sich das aber in Richtung Vyper oder SolidityX verändern, da beide per default sicherer sein sollen als Solidity.
### Migrations-Ordner
Was ist eine Truffle-Migration?
- Im Grunde ist es ein Skript, welches definiert, wie die Smart Contracts auf der Blockchain eingesetzt/verteilt werden. (Deployment)
Warum sind diese Migrationen notwendig?
- Mit der Komplexität des Projekts steigt zugleich auch die Schwierigkeit des Deployments auf der Blockchain.
Ein kleines Beispiel:
Wir haben die Smart Contracts A, B und C.
Der Smart Contract C beinhaltet eine Referenz auf den Smart Contract A und benötigt die Adresse des Smart Contracts B in seinem Konstruktor.
Bei diesem Beispiel müssen die Smart Contracts nicht nur sequenziell angwendet werden, sondern sie haben auch gegenseitige Querverweise. Zusammengefasst gesagt: Migrationen erlauben uns diesen Prozess zu automatisieren.
Eine Beispielmigration für das obige Beispiel könnte wie folgend aussehen:
```javascript
var One = artifacts.require("One");
var Two = artifacts.require("Two");
var Three = artifacts.require("Three");
module.exports = function(deployer) {
deployer.deploy(One).then(function() {
deployer.deploy(Two).then(function() {
deployer.deploy(Three, One.address);
})
});
};
```
Zusätzlich erlauben Migrationen weitere Dinge wie:
- Max Gas für Deployments festlegen
- Herkunftsadresse (`from address`) von Deployments verändern
- Librarys installieren/anwenden
- Aufrufen beliebiger Smart Contract Funktionen
Wie ihr vielleicht bereits gesehen habt, beinhaltet das MetaCoin-Projekt eine Datei namens `1_initial_migration.js`. Diese Datei verteilt den `Migrations.sol` Smart Contract auf der Blockchain.
Normalerweise muss diese Datei nicht geändert werden nachdem das Projekt einmal initialisiert wurde.
### Test-Ordner
Smart Contracts MÜSSEN getestet werden. Es geht schließlich um viel Geld und es gab bereits genügend Vorfälle bei denen Smart Contracts Lücken und Fehler aufwiesen.
Um diesen Prozess zu automatisieren liefert Truffle ein eingebautes Testframework mit. Es erlaubt Tests entweder in Solidity oder Javascript zu schreiben.
Schaut euch die Beispiele am besten etwas genauer an, da ihr in einer späteren Aufgabe auch noch Tests schreiben müsst.
Falls ihr Tests in Solidity schreibt, könnt ihr eure Smart Contracts mit der folgenden Zeile importieren:
`import "../contracts/MetaCoin.sol";`
Beim Schreiben von Tests in Javascript importiert ihr diese mit der `artifacts.require()` Hilfsfunktion:
`var MetaCoin = artifacts.require("./MetaCoin.sol");`
### Konfigurationsdatei
Die Konfigurationsdatei heißt entweder `truffle.js` oder `truffle-config.js`.
In der Konfigurationsdatei können verschiedene Dinge festgelegt und verändert werden:
- Umgebungsvariablen für Entwicklung, Testnetz und Produktion wie Netzwerkadressen, Netzwerk-IDs, Max Gas,...
- Kompilerversion und -parameter (für solc)
- Packetmanagment (für EthPM)
- Projektbeschreibung (Projektname, -autor)
## Ausführen des Codes
- Zum Kompilieren der Smart Contracts:
`truffle compile`
- Zum Durchführen der Migrationen:
`truffle migrate`
Es können aber auch spezifische Umgebungen angegeben werden:
`truffle migrate --network live`
Zum Rekompilieren und Migrieren aller Smart Contracts (nicht nur von Änderungen) kann folgender Befehl verwendet werden:
`truffle migrate --reset --compile-all`
- Zum Testen der Smart Contracts:
`truffle test`
Oder um spezifische Tests laufen zu lassen:
`truffle test ./path/to/TestFile.sol`
Testet alle drei Kommandos, wobei die Migration einen Fehler ausgeben sollte, da wir aktuell noch kein Ethereum Testnetz gestartet haben.
# Aufgabe 2 Erstellen eines ersten Smart Contracts mit Solidity und Truffle
Nachdem wir jetzt Truffle kennen gelernt haben, schreiben wir nun einen ersten Smart Contract in Solidity. Es soll dabei ein einfaches "Hello Name"-Projekt entstehen.
Wir haben dafür drei Anforderungen und Vorraussetzungen:
- 2 Zustandsvariablen werden benötigt - der Name und die Ethereum-Adresse des Besitzers
- der Besitzer kann den Namen ändern und hinzufügen
- Jeder kann den Wert der Zustandsvariablen (insbesondere den Namen) bekommen
## Initialiseren des Projekts.
Erstellt einen Ordner und initalisiert Truffle darin mit den folgenden Befehlen:
```
mkdir hello-solidity
cd hello-solidity
truffle init
```
Falls dies erfolgreich war, solltet ihr eine Ausgabe mit der Nachricht `Unbox successful. Sweet!`
Ihr solltet nun eine ähnliche Ordnerstruktur wie in Aufgabe 1 haben.
## Ganache(-CLI)
Ganache ist eine lokale, eigenständige Ethereum Blockchain, welche man verwenden kann um Smart Contracts zu verteilen, Applikationen zu entwickeln und Tests laufen zu lassen.
Wir verwenden in dieser und folgender Aufgabe die Kommandozeilenvariante dieses Tools um unsere Smart Contracts zu testen. Mehr Infos zu Ganache und auch zur Desktopvariante davon findet ihr [hier](https://www.trufflesuite.com/docs/ganache/overview).
Ihr solltet nun mit dem folgenden Befehl eure lokale Blockchain in einem zweiten Terminalfenster starten:
`ganache-cli`
Notiert euch am besten die IP und den Port, welcher ausgegeben wird. (Normalerweise: 127.0.0.1:8545)
## Konfiguration von Truffle
Wir nehmen ein paar kleinere Anpassungen in der Konfigurationsdatei vor um die Verbindung zu Ganache aufzubauen und gleichzeitig legen wir fest, dass wir die Version 0.5.10 des Kompilers verwenden wollen.
Eure `truffle-config.js` soltle dann wie folgend aussehen:
```javascript
module.exports = {
// Configure your networks
networks: {
// development network is default for truffle
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
}
},
// Configure your compilers
compilers: {
solc: {
version: "0.5.10", // Fetch exact version from solc-bin (default: truffle's version)
}
}
}
```
## Erstellen des Smart Contracts
1. Erstellt im Contracts-Ordner eine neue Datei namens `Hello.sol`. Diese wird unseren Smart Contract beinhalten.
2. Wählen der Compilerversion - `pragma solidity`
Zu Beginn eines Smart Contracts sollten wir immer die Version des Compilers spezifizieren. Dafür verwenden wir die folgenden Zeile:
`pragma solidity ^0.5.0;`
Dies bedeutet, dass die minimale Version des von uns unterstützten Compilers die Version 0.5.0 ist. Das `^` bedeutet, dass auch jede Version 0.5.X möglich ist, da eine Änderung der PATCH-Version nur rückwärtskompatible Änderungen wie Bugfixes erlaubt. Würden wir es mit einer Compilerversion von 0.6.0 oder höher oder 0.4.X versuchen, würden wir einen Fehler erhalten.
Wichtig! Die hier spezifizierte Compilerversion sagt nur aus, mit welcher Version diese Datei kompiliert werden muss. Dies ändert aber nicht die verwendete Version in Truffle. Diese wird in der Datei `truffle.config.js` festgelegt.
3. Deklaration der Variablen
Anschließend kann der `Hello`-Kontrakt geschrieben werden. Dies geschieht durch das Wort `contract` gefolgt von dem Namen des Smart Contracts. Dieser ist unabhängig vom Dateinamen, stimmt in unserem Fall aber überein.
Innnerhalb des Smart Contracts beginnen wir mit der Deklaration der Zustandsvariablen. Solidity ist ein statische typisierte Programmiersprache. Zuerst definieren wir den Typ der Variablen und dann ihren Namen. In dieser Aufgabe bedeutet dies für uns, dass wir Variablen mit der Ethereumadresse des Besitzers und den String mit dem Namen deklarieren.
```javascript
pragma solidity ^0.5.0;
contract Hello {
address private owner;
string private name;
}
```
In einem Smart Contract können wir auch folgende andere Variablentypen verwenden:
- bool
- int oder uint
- contract
- array
- struct
- enum
- mapping
Mehr Informationen zu den verschiedenen Datentypen findet ihr in der Dokumentation von Solidity [hier](https://solidity.readthedocs.io/en/v0.5.10/types.html).
4. Konstruktor
Unterhalb der Variablen definieren wir eine Konstruktorfunktion, welche für die Verteilung des Smart Contracts auf dem Blockchainnetzwerk aufgerufen wird. Im Konstruktor ordnen wir die Ethereumadresse, welche die Verteilung gestartet, der Variable `owner` zu.
Um diesen Absender der aktuellen Nachricht herauszufinden können wir `msg.sender` aufrufen.
```javascript
constructor() public {
owner = msg.sender;
}
```
Ein Konstruktor zu schreiben ist im Allgemeinen optional. Wenn unser Smart Contract direkt nach seiner Erstellung keine Aktion ausführen soll, können wir ihn einfach weglassen. Für unseren konkreten `Hello World`-Smart Contract wird er allerdings benötigt!
Füge daher obige Zeilen innerhalb des Contracts unterhalb der Variablen ein.
5. Sichtbarkeit von Variablen und Funktionen (public, private, external und internal)
Es gibt vier verschiedene Arten der Sichtbarkeit (Zugriffsmodifikatoren): `public, private, external` und `internal`. Wir müssen dies für für alle Variablen und Funktionen festlegen. Der Einfachheit halber nehmenlegen wir fest, dass alle Variablen in unserem Smart Contract `private` sind (was nicht bedeutet, dass sie für andere Benutzer der Blockchain nicht sichtbar wären!!) und alle Funktionen `public`. In der Dokumentation von Solidity findet ihr auch in diesem Fall mehr dazu.
6. Smart Contract Funktionen
Für unseren Smart Contract erstellen wir die Folgenden Funktionen:
- setName — setzt die Variable `name` auf einen neuen Wert
```javascript
function setName (string memory _name) public {
require (msg.sender == owner, "You are not the owner!");
name = _name;
}
```
- getName — gibt den Wert der Variable `name` zurück
```javascript
function getName() public view returns (string memory) {
return name;
}
```
- sayHello — gibt eine Grußnachricht aus
```javascript
function sayHello() public view returns (string memory, string memory)
{
return ("Hello Solidity! My name is:", name);
}
```
In Funktionen, welche nicht den Zustand verändern - in unserem Fall wären das `getName()` und `sayHello()` - fügen wir das `view`-Attribut nach den Zugriffsmodifikatoren ein.
Zusätzlich spezifizieren wir für die Funktionsparameter den Speicherort der Daten:
- `memory` — Laufzeit ist auf den Funktionsaufruf beschränkt
- `storage` — Ort, an welchem die Zustandsvariablen gespeichert werden
- `calldata` — Speicherort spezieller Daten
Damit haben wir den ersten Smart Contract selbst geschrieben.
## Kompilieren und Deployment des Smart Contracts
1. Hinzufügen der Smart Contract Migrationsdatei
Im Migrationsordner erstellen wir eine Datei namens `2_deploy_contracts.js`, in welcher wir den Verteilungsvorgang des Smart Contracts genauer definieren. In unserem Fall, da wir nur einen Smart Contract haben, sieht das ganze wie folgend aus:
```javascript
var Hello = artifacts.require ("Hello.sol");
module.exports = function (deployer) {
deployer.deploy (Hello);
};
```
2. Deployment
Zuerst kontrolliert, ob ihr - wie weiter oben beschrieben und gefordert - euer lokales Ethereumnetzwerk mit Ganache bereits am Laufen habt!
Danach öffnet ihr ein Terminal und kompiliert das ganze:
`truffle compile`
Dadurch überprüfen wir ob unsere Smart Contracts (in unserem Fall genau einer) korrekt kompilieren. Im Erfolgsfall solltet ihr eine Nachricht ähnlich der folgenden sehen:
```
Compiling your contracts...
===========================
> Compiling ./contracts/Hello.sol
> Compiling ./contracts/Migrations.sol
> Artifacts written to /home/.../hello_solidity/build/contracts
> Compiled successfully using:
- solc: 0.5.10+commit.5a6ea5b1.Emscripten.clang
```
Wir können nun überprüfen, ob innerhalb des Projekt ein `build`-Ordner angelegt wurde. Darin sollte sich ein Ordner namens `contracts` mit zwei JSON-Dateien befinden.
Falls nun alles erfolgreich kompiliert hat, können wir den Smart Contract auf der Blockchain mit dem folgenden Befehl verteilen:
`truffle migrate`
Dieser Befehlt startet die Migrationen, welche den Verteilprozess beinhalten. Als Ausgabe bekommen wir verschiedene Informationen über die korrekte Migration. Diese beinhalten unter anderem die Adresse des Smart Contracts.
## Interaktionen mit dem Smart Contract
1. Um mit dem Smart zu interagieren verwenden wir die Trufflekonsole. Diese kann mit dem folgenden Befehl gestartet werden:
`truffle console`
Jetzt sollte der `truffle(development)`-Modus in unserem Terminal erscheinen. Zum Beenden verwenden wir Strg+c oder `.exit`.
2. Zuerst speichern wir die Instanz des `Hello` Smart Contracts in einer Variablen namens app und rufen diese dann auf:
```javascript
let app = await Hello.deployed()
app
```
Durch den Aufruf von `app` bekommen wir verschiedene Informationen über die Smart Contract Instanz ausgegeben.
3. Nun fügen wir unseren Namen in die Zustandsvariable ein indem wir die Funktion `setName()` aufrufen:
`app.setName("Stefan")`
4. Danach überprüfen wir das Ergebnis der vorhergehenden Operation indem wir die Funktion `getName()` aufrufen:
`app.getName()`
Dies sollte den zuvor eingegebenen Namen ausgaben.
5. Zum Abschluss können wir noch unsere Grußfunktion ausführen:
`app.sayHello()`
Die Ergebnis sollte dann ähnlich zu dem folgenden aussehen:
`Result { '0': 'Hello Solidity! My name is: ', '1': 'Stefan' }`
Wir verzichten hier darauf die Strings zusammenzuführen, da dies innerhalb der Blockchain unnötig Gas kosten würde.
Damit habt ihr euren ersten Smart Contract erstellt und in einem Blockchainnetzwerk verteilt.
Ihr könnt nun die Trufflekonsole via `.exit` verlassen.
\ No newline at end of file
# Aufgabe 3 Testen von Smart Contracts
In dieser Aufgabe gehen wir nun intensiver auf das Testen von Smart Contracts ein. Wie bereits in Aufgabe 1 erwähnt ist das Testen wohl der wichtigste Aspekt von qualitativ hochwertigen und vor allem sicheren Smart Contracts bei denen es um viel Geld gehen kann.
Wir implementieren eine Art Flohmarkt, also ein Smart Contract in welchem gebrauchte Gegegenstände verkauft werden können.
## Initalisieren des Projekts
Öffnet wieder ein Terminal und erstellt einen Projektordner mit Truffle:
```
mkdir Flohmarkt
cd Flohmarkt
truffle init
```
Eure Ausgabe solle so aussehen:
```
✔ Preparing to download
✔ Downloading
✔ Cleaning up temporary files
✔ Setting up box
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
```
Und ihr solltet auch wieder die übliche Truffle-Projektstruktur erhalten haben.
## Vorbereiten der Testumgebung
Wir verwenden wie bereits in den letzten Aufgaben wieder das Tool `ganache-cli` für das Testen des Smart Contracts in einer lokalen Blockchain.
Falls ihr das Terminal mit der laufenden Version von Ganache bereits geschlossen habt, startet die Umgebung bitte erneut mit:
`ganache-cli`
Eure Ausgabe sollte dann ähnlich zu der folgenden aussehen:
```markdown
Ganache CLI v6.5.0 (ganache-core: 2.6.0)
Available Accounts
==================
(0) 0x1003bc1902a708ea9e3835a2af758a675fb2e7f6 (~100 ETH)
(1) 0x5a0794fe748859675e2bad51e2e73c599b7d75aa (~100 ETH)
(2) 0x9a72850f3ba5ef2a007f08e8fd8948ba94a68d7c (~100 ETH)
(3) 0x51b242b225ceb0ef2b97aebd91e541c04daa7aaa (~100 ETH)
(4) 0xe8ae6354c28d9dcce5b4db1dc59bb4eb7e0a1ee6 (~100 ETH)
(5) 0xf54a7941067a3781c7753b38bf2703218c46ca47 (~100 ETH)
(6) 0x5b403da9cd228224f9644c96eae45c59cdd90e75 (~100 ETH)
(7) 0xb995e9108d1d3af7c049a88c561e0a98836d5649 (~100 ETH)
(8) 0x0c6a2b46463f00a8d7bcd0f78d50310777e5f0a7 (~100 ETH)
(9) 0x4f899d0be96f24cfa2c58fa5b63dd07baa74ede3 (~100 ETH)