Vorwort
Im vorherigen Artikel “Solidity Smart Contract Entwicklung - Grundlagen” haben wir die grundlegende Syntax von Solidity kennengelernt und verstanden, dass wir mit Frameworks wie Brownie und HardHat debuggen können. In einem weiteren Artikel “Solidity Smart Contract Entwicklung - Beherrschung von Web3.py” haben wir auch direkt mit unserem lokalen Ganache-Node mittels Web3.py interagiert.
Ursprünglich hatte ich geplant, aufgrund meiner größeren Vertrautheit mit Python, das Brownie-Framework für die weitere Entwicklung zu verwenden. Nach einiger Recherche stellte ich jedoch fest, dass in der Branche überwiegend das HardHat-Framework verwendet wird, das auch mehr Erweiterungen bietet. Zudem wurde das Solidity-Tutorial, dem ich folge, auf eine Javascript-Version aktualisiert, weshalb ich beschloss, es zu erlernen.
Um die Prinzipien besser zu verstehen und eine gute Grundlage für unsere spätere Verwendung des Frameworks zu schaffen, werden wir diesmal ethers.js verwenden, um mit unserem auf der Alchemy-Plattform bereitgestellten Rinkeby-Testnetzwerk zu interagieren. Wir werden die grundlegende Vertragskompilierung, die Bereitstellung im Rinkeby-Netzwerk und die Interaktion mit dem Vertrag implementieren.
Sie können hier auf das Code-Repository für dieses Test-Demo zugreifen.
ethers.js
ethers.js ist eine Open-Source-Bibliothek für Javascript, die mit dem Ethereum-Netzwerk interagieren kann. Ihre GitHub-Adresse lautet ethers.io/ethers.js, und Sie können ihre offizielle Dokumentation für die Verwendung besuchen.
Installation
Wir können ethers.js
mit yarn wie folgt installieren:
yarn add ethers
Verwendung
Importieren Sie die Bibliothek mit require
, um sie zu verwenden
const ethers = require('ethers');
Kompilierung des Solidity-Vertrags
Quellcode des Vertrags
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract SimpleStorage {
uint256 favoriteNumber;
bool favoriteBool;
struct People {
uint256 favoriteNumber;
string name;
}
People public person = People({favoriteNumber: 2, name: "Arthur"});
People[] public people;
mapping(string => uint256) public nameToFavoriteNumber;
function store(uint256 _favoriteNumber) public returns (uint256) {
favoriteNumber = _favoriteNumber;
return favoriteNumber;
}
function retrieve() public view returns (uint256) {
return favoriteNumber;
}
function addPerson(string memory _name, uint256 _favoriteNumber) public {
people.push(People({favoriteNumber: _favoriteNumber, name: _name}));
nameToFavoriteNumber[_name] = _favoriteNumber;
}
}
Dies ist ein einfacher Speichervertrag, der ein People-Strukturobjekt verwendet, um den Namen einer Person und ihre Lieblingszahl zu speichern, ein Array verwendet, um Informationen für mehrere Personen zu speichern, und Methoden zum Hinzufügen und Suchen bereitstellt.
Lesen der Vertragssquelldatei
Nachdem wir das Schreiben und die Syntaxprüfung des Solidity-Vertrags durch VSCode oder andere Editoren abgeschlossen haben, müssen wir den Vertrag in eine ABI-Datei und Bytecode kompilieren.
Wir können das solc
-Kommandozeilentool über yarn
für die Bearbeitung installieren, und wir können die entsprechende Version wählen. Der Befehl lautet wie folgt:
yarn add [email protected]
Nach der Installation können wir den solcjs
-Befehl zur Kompilierung verwenden. Der Befehl lautet wie folgt:
yarn solcjs --bin --abi --include-path node_modules/ --base-path . -o . SimpleStorage.sol
Da das Kompilieren von Verträgen eine häufige Operation ist, können wir den compile
-Skriptbefehl in package.json
wie folgt konfigurieren:
"scripts": {
"compile": "yarn solcjs --bin --abi --include-path node_modules/ --base-path . -o . SimpleStorage.sol"
}
Danach müssen Sie nur noch yarn compile
ausführen, um die Vertragskompilierungsdateien zu generieren.
Erhalt der Kompilierungsergebnisse
Nach der Kompilierung werden ABI- und Bytecode-Dateien generiert, mit .bin
bzw. .abi
als Suffixe.
Erhalt von Bytecode und ABI
Die Bereitstellung und Interaktion von Solidity-Verträgen erfordern zwei Teile: Bytecode und ABI. Wir können sie durch den folgenden Code in entsprechende Variablen für nachfolgende Operationen schreiben.
const fs = require('fs-extra');
const abi = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.abi", "utf-8");
const binary = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.bin", "utf-8");
Erstellung einer Rinkeby-Testnetzwerkumgebung (Alchemy)
Das Debuggen von Smart Contracts erfordert die Bereitstellung des Vertrags in einer tatsächlichen Kette. Wir wählen die Bereitstellung im Rinkeby-Testnetzwerk auf der Alchemy-Plattform für nachfolgendes Debugging und Entwicklung.
Alchemy-Plattform
Zunächst besuchen wir die offizielle Alchemy-Website, registrieren uns und melden uns an, und wir sehen ihr Dashboard, das alle erstellten Anwendungen anzeigt.
Nach der Installation wählen Sie Create App, um schnell einen Rinkeby-Testnetzwerk-Node zu erstellen.
Nach der Erstellung klicken Sie auf View Details, um die detaillierten Informationen der App zu sehen, die wir gerade erstellt haben. Klicken Sie oben rechts auf View Key, um unsere Node-Informationen abzufragen. Wir müssen die HTTP-URL für die spätere Verbindung notieren.
Erstellung eines Rinkeby-Testkontos (MetaMask)
MetaMask
Nachdem wir die Rinkeby-Testnetzwerkumgebung erstellt haben, müssen wir ein Konto über MetaMask erstellen, einige Test-Token erhalten und den privaten Schlüssel des Kontos für die spätere Verwendung notieren.
Erhalt von Test-Token
Nach der Erstellung eines Kontos benötigen wir einige Test-Token für die nachfolgende Entwicklung und das Debugging. Wir können sie über die folgenden URLs erhalten:
Verbindung zum Test-Node und Wallet
Verbindung zum Node
ethers.js
bietet eine Bibliothek, die sich leicht mit unserem Test-Node verbinden lässt, wobei process.env.ALCHEMY_RPC_URL
die HTTP-URL der App ist, die wir auf der Alchemy-Plattform erstellt haben:
const ethers = require('ethers');
const provider = new ethers.providers.JsonRpcProvider(process.env.ALCHEMY_RPC_URL);
Verbindung zur Wallet
ethers.js
bietet auch eine Methode, um sich mit unserer Test-Wallet zu verbinden, wobei process.env.RINKEBY_PRIVATE_KEY
der private Schlüssel ist, den wir aus MetaMask kopiert haben.
const ethers = require('ethers');
const wallet = new ethers.Wallet(
process.env.RINKEBY_PRIVATE_KEY,
provider
);
Bereitstellung des Solidity-Vertrags
Erstellung des Vertrags
Wir können einen Vertrag über die ethers.js
-Bibliothek erstellen.
const contractFactory = new ethers.ContractFactory(abi, binary, wallet);
Bereitstellung des Vertrags
Nachfolgend werden wir erläutern, wie man einen Vertrag über die ethers.js
-Bibliothek bereitstellt, wobei die ABI- und BIN-Dateien des SimpleStorage
-Vertrags bereits im obigen Code eingelesen wurden.
Erstellung des Vertrags
const contractFactory = new ethers.ContractFactory(abi, binary, wallet);
Bereitstellung des Vertrags
const contract = await contractFactory.deploy();
await contract.deployTransaction.wait(1);
Interaktion mit dem Vertrag
Wir können auch mit dem Vertrag über ethers.js
interagieren.
retrieve()
const currentFavoriteNumber = await contract.retrieve();
store()
const transactionResponse = await contract.store("7")
const transactionReceipt = await transactionResponse.wait(1);
Konstruktion einer Transaktion aus Rohdaten
Zusätzlich zum direkten Aufruf von Methoden zur Bereitstellung von Verträgen können wir auch selbst Transaktionen konstruieren.
Konstruktion der Transaktion
const nonce = await wallet.getTransactionCount();
const tx = {
nonce: nonce,
gasPrice: 20000000000,
gasLimit: 1000000,
to: null,
value: 0,
data: "0x" + binary,
chainId: 1337,
};
Signierung der Transaktion
const signedTx = await wallet.signTransaction(tx);
Senden der Transaktion
const sentTxResponse = await wallet.sendTransaction(tx);
await sentTxResponse.wait(1);
Fazit
Dies sind die Schritte zur Interaktion mit dem Rinkeby-Testnetzwerk von Alchemy über die ethers.js
-Bibliothek. In der tatsächlichen Projektentwicklung verwenden wir im Allgemeinen nicht direkt Bibliotheken wie ethers.js
, sondern weiter gekapselte Frameworks wie Brownie und HardHat. Das Verständnis der Verwendung von Bibliotheken wie Web3.py
oder ethers.js
ist jedoch ebenfalls sehr wichtig. Ich werde in Zukunft die Verwendung des HardHat-Frameworks weiter erläutern.