Verwendung von Ethereum-Bibliotheken zur Bereitstellung (Deploy) von Smart Contracts auf Moonbeam
Einführung
Diese Anleitung erklärt die Verwendung von drei verschiedenen Ethereum-Bibliotheken, um eine Transaktion auf Moonbeam manuell zu signieren und zu senden. Die drei Bibliotheken, die in diesem Tutorial behandelt werden, sind:
Außerdem werden zwei weitere Bibliotheken verwendet, um den Smart Contract zu erstellen:
- Solc-js um Solidity Smart Contracts mit JavaScript zu kompilieren
- Py-solc-x um Solidity Smart Contracts mit Python zu kompilieren
Hinweis In den Beispielen wird davon ausgegangen, dass Sie eine auf MacOS oder Ubuntu 18.04 basierende Umgebung haben. Für Windows müssen die Beispiele entsprechend angepasst werden .
Voraussetzungen prüfen
Die Beispiele, die sowohl web3.js als auch ethers.js verwenden, erfordern eine vorherige Installation von Node.js und NPM. Das Beispiel mit web3.py erfordert Python und PIP. Zum Zeitpunkt der Erstellung dieser Anleitung wurden folgende Versionen verwendet:
- Node.js v15.10.0
- NPM v7.5.3
- Python v3.6.9 (web3 erfordert Python >= 3.5.3 and < 4)
- PIP3 v9.0.1
Erstellen Sie ein Verzeichnis, um alle relevanten Dateien zu speichern:
mkdir incrementer && cd incrementer/
Für die JavaScript-Bibliotheken können Sie zunächst eine einfache package.json
Datei erstellen (nicht erforderlich):
npm init --yes
Installieren Sie im Verzeichnis die entsprechende Bibliothek und den Solidity-Compiler (web3.py und py-solc-x werden im Standardverzeichnis von PIP3 installiert):
Web3.js
npm i web3 npm i [email protected]
Ethers.js
npm i ethers npm i [email protected]
Web3.py
pip3 install web3 pip3 install py-solc-x
Die, zum Zeitpunkt der Veröffentlichung dieser Anleitung, verwendeten Versionen waren:
- Web3.js v1.33 (
npm ls web3
) - Ethers.js v5.0.31 (
npm ls ethers
) - Solc (JS) v0.8.0 (
npm ls solc
) - Web3.py v5.17.0 (
pip3 show web3
) - Py-solc-x v1.1.0 (
pip3 show py-solc-x
)
Die Einrichtung für dieses Beispiel ist relativ einfach und enthält die folgenden Dateien:
- Incrementer.sol — die Datei mit unserem Solidity-Code
- compile.* — erstellt den Contract mit dem Solidity Compiler
- deploy.*: es wird die Bereitstellung auf unserem lokalen Moonbeam-Node verarbeiten
- get.* — es ruft den Node auf, um den aktuellen Wert der Nummer abzurufen
- increment.* — es wird eine Transaktion durchgeführt, um die auf dem Moonbeam-Node gespeicherte Nummer zu erhöhen
- reset.* — die anzurufende Funktion, die die gespeicherte Nummer auf Null zurücksetzt
Die Contractsdatei
Der verwendete Contract ist ein einfacher Inkrementer, der willkürlich Incrementer.sol genannt wird, den Sie hier finden. Der Solidity-Code sieht wie folgt aus:
pragma solidity ^0.8.0; contract Incrementer { uint256 public number; constructor(uint256 _initialNumber) { number = _initialNumber; } function increment(uint256 _value) public { number = number + _value; } function reset() public { number = 0; } }
Die constructor
Funktion, die ausgeführt wird, wenn der Contract bereitgestellt wird, legt den Anfangswert der on-chain gespeicherten Zahlenvariablen fest (Standardwert ist 0). Dieincrement
Funktion fügt den angegebenen _value
zur aktuellen Zahl hinzu, aber es muss eine Transaktion gesendet werden, die die gespeicherten Daten modifiziert. Schließlich setzt die reset
Funktion den gespeicherten Wert auf Null zurück.
Hinweis
Dieser Contract ist nur ein einfaches Beispiel zur Veranschaulichung und behandelt keine Werte.
Kompilierung des Contracts
Der einzige Zweck der Kompilierungsdatei besteht darin, den Solidity-Compiler zu verwenden, um den Bytecode und die Schnittstelle (ABI) unseres Contracts auszugeben. Den Codeausschnitt für jede Bibliothek finden Sie hier (sie wurden compile.*
genannt):
- Web3.js: compile.js
- Ethers.js: compile.js
- Web3.py: compile.py
Hinweis
Die Kompilierungsdatei für beide JavaScript-Bibliotheken ist dieselbe, da sie sich die JavaScript-Bindungen für den Solidity-Compiler (gleiches Paket) teilen.
Web3.js
const fs = require('fs'); const solc = require('solc'); // Get Path and Load Contract const source = fs.readFileSync('Incrementer.sol', 'utf8'); // Compile Contract const input = { language: 'Solidity', sources: { 'Incrementer.sol': { content: source, }, }, settings: { outputSelection: { '*': { '*': ['*'], }, }, }, }; const tempFile = JSON.parse(solc.compile(JSON.stringify(input))); const contractFile = tempFile.contracts['Incrementer.sol']['Incrementer']; // Export Contract Data module.exports = contractFile;
Ethers.js
const fs = require('fs'); const solc = require('solc'); // Get Path and Load Contract const source = fs.readFileSync('Incrementer.sol', 'utf8'); // Compile Contract const input = { language: 'Solidity', sources: { 'Incrementer.sol': { content: source, }, }, settings: { outputSelection: { '*': { '*': ['*'], }, }, }, }; const tempFile = JSON.parse(solc.compile(JSON.stringify(input))); const contractFile = tempFile.contracts['Incrementer.sol']['Incrementer']; // Export Contract Data module.exports = contractFile;
Web3.py
import solcx # If you haven't already installed the Solidity compiler, uncomment the following line # solcx.install_solc() # Compile contract temp_file = solcx.compile_files('Incrementer.sol') # Export contract data abi = temp_file['Incrementer.sol:Incrementer']['abi'] bytecode = temp_file['Incrementer.sol:Incrementer']['bin']
Web3.js und Ethers.js
Im ersten Teil des Skripts wird der Pfad des Contracts abgerufen und dessen Inhalt gelesen.
Als nächstes wird das Eingabeobjekt (input object) des Solidity-Compilers erstellt und als Eingabe an die Funktion solc.compile
übergeben.
Extrahieren Sie schließlich die Daten des Incrementer
Contracts der Incrementer.sol
Datei und exportieren Sie sie, damit das deployment script sie verwenden kann.
Web3.py
Im ersten Teil des Skripts wird die Contractsdatei mit der Funktion solcx.compile_files
kompiliert. Beachten Sie, dass sich die Contractsdatei im selben Verzeichnis wie das Kompilierungsskript befindet.
Hinweis
Wenn Sie die Datei compile.py
ausführen, erhalten Sie möglicherweise eine Fehlermeldung, die besagt, dass Solc
installiert werden muss. Wenn dies der Fall ist, entkommentieren Sie die Zeile in der Datei, die solcx.install_solc()
ausführt, und führen Sie die Kompilierungsdatei erneut mitpython3 compile.py
aus. Weitere Informationen finden Sie hier.
Als nächstes, nach Abschluss des Skripts, werden die Contractssdaten exportiert. In diesem Beispiel wurden nur die Schnittstelle (ABI) und der Bytecode definiert.
Bereitstellung (deploying) des Contracts
Unabhängig von der Bibliothek ist die Strategie zum Bereitstellen des kompilierten Smart Contracts ähnlich. Eine Contractinstanz wird unter Verwendung ihrer Schnittstelle (ABI) und ihres Bytecodes erstellt. Von dieser Instanz wird eine Bereitstellungsfunktion (deployment function) verwendet, um eine signierte Transaktion zu senden, die den Contract bereitstellt. Den Codeausschnitt für jede Bibliothek finden Sie hier (sie wurden deploy.*
genannt):
Die Bereitstellungsdatei besteht aus zwei Abschnitten. Im ersten Abschnitt ("Define Provider & Variables") werden die zu verwendende Bibliothek sowie die ABI und der Bytecode des Contracts importiert. Außerdem werden der Anbieter und das Konto (provider and account) (mit dem private key) definiert. Beachten Sie, dass providerRPC
sowohl den Standard-development node RPC endpoint als auch endpoint für Moonbase Alpha hat.
Der zweite Abschnitt ("Deploy Contract") wird die Contractsbereitstellung beschrieben. Beachten Sie, dass für dieses Beispiel der Anfangswert number
auf 5 gesetzt wurde.
Web3.js
const Web3 = require('web3'); const contractFile = require('./compile'); /* -- Define Provider & Variables -- */ // Provider const providerRPC = { development: 'http://localhost:9933', moonbase: 'https://rpc.testnet.moonbeam.network', }; const web3 = new Web3(providerRPC.development); //Change to correct network // Variables const account_from = { privateKey: 'YOUR-PRIVATE-KEY-HERE', address: 'PUBLIC-ADDRESS-OF-PK-HERE', }; const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; /* -- Deploy Contract -- */ const deploy = async () => { console.log(`Attempting to deploy from account ${account_from.address}`); // Create Contract Instance const incrementer = new web3.eth.Contract(abi); // Create Constructor Tx const incrementerTx = incrementer.deploy({ data: bytecode, arguments: [5], }); // Sign Transacation and Send const createTransaction = await web3.eth.accounts.signTransaction( { data: incrementerTx.encodeABI(), gas: await incrementerTx.estimateGas(), }, account_from.privateKey ); // Send Tx and Wait for Receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log( `Contract deployed at address: ${createReceipt.contractAddress}` ); }; deploy();
Ethers.js
const ethers = require('ethers'); const contractFile = require('./compile'); /* -- Define Provider & Variables -- */ // Provider const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9933', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.testnet.moonbeam.network', chainId: 1287, }, }; const provider = new ethers.providers.StaticJsonRpcProvider( providerRPC.development.rpc, { chainId: providerRPC.development.chainId, name: providerRPC.development.name, } ); //Change to correct network // Variables const account_from = { privateKey: 'YOUR-PRIVATE-KEY-HERE', }; const bytecode = contractFile.evm.bytecode.object; const abi = contractFile.abi; // Create Wallet let wallet = new ethers.Wallet(account_from.privateKey, provider); /* -- Deploy Contract -- */ // Create Contract Instance with Signer const incrementer = new ethers.ContractFactory(abi, bytecode, wallet); const deploy = async () => { console.log(`Attempting to deploy from account: ${wallet.address}`); // Send Tx (Initial Value set to 5) and Wait for Receipt const contract = await incrementer.deploy([5]); await contract.deployed(); console.log(`Contract deployed at address: ${contract.address}`); }; deploy();
Web3.py
from compile import abi, bytecode from web3 import Web3 # # -- Define Provider & Variables -- # # Provider provider_rpc = { 'development': 'http://localhost:9933', 'alphanet': 'https://rpc.testnet.moonbeam.network', } web3 = Web3(Web3.HTTPProvider(provider_rpc['development'])) # Change to correct network # Variables account_from = { 'private_key': 'YOUR-PRIVATE-KEY-HERE', 'address': 'PUBLIC-ADDRESS-OF-PK-HERE', } # # -- Deploy Contract -- # print(f'Attempting to deploy from account: { account_from["address"] }') # Create Contract Instance Incrementer = web3.eth.contract(abi=abi, bytecode=bytecode) # Build Constructor Tx construct_txn = Incrementer.constructor(5).buildTransaction( { 'from': account_from['address'], 'nonce': web3.eth.getTransactionCount(account_from['address']), } ) # Sign Tx with PK tx_create = web3.eth.account.signTransaction(construct_txn, account_from['private_key']) # Send Tx and Wait for Receipt tx_hash = web3.eth.sendRawTransaction(tx_create.rawTransaction) tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash) print(f'Contract deployed at address: { tx_receipt.contractAddress }')
Hinweis
Das Skript deploy.* stellt die Contractadresse als Ausgabe bereit. Dies ist praktisch, da es für die Contractinteraktionsdateien (contract interaction files) verwendet wird.
Web3.js
Im ersten Abschnitt des Skripts wird die web3
Instanz (oder der Anbieter (provider)) mithilfe des Web3-Konstruktors mit dem provider RPC erstellt. Indem Sie den Provider-RPC ändern, der dem Konstruktor übergeben wurde, können Sie auswählen, an welches Netzwerk Sie die Transaktion senden möchten.
Der private Schlüssel (private key) und die damit verbundene public Adresse werden zur Signierung der Transaktion bzw. zur Protokollierung (logging) definiert. Es wird nur der private Schlüssel benötigt. Außerdem werden der Bytecode und die Schnittstelle (ABI) des Contracts aus dem Export der Kompilierung abgerufen.
Im zweiten Abschnitt wird durch die Bereitstellung des ABI eine Contractinstanz erstellt. Als nächstes wird die Funktion deploy
verwendet, die den Bytecode und die Argumente der Konstruktorfunktion benötigt. Dadurch wird das Transaktionsobjekt (constructor transaction object) des Konstruktors generiert.
Anschließend kann die Konstruktortransaktion (constructor transaction) mit der Methode web3.eth.accounts.signTransaction()
signiert werden. Das Datenfeld entspricht dem Bytecode, und die Eingabeargumente des Konstruktors werden zusammen codiert. Beachten Sie, dass der Wert von Gas mit der Option estimateGas()
innerhalb der Konstruktortransaktion (constructor transaction) ermittelt wird.
Die unterschriebene Transaktion wird versendet und die Cotractadresse wird im Terminal angezeigt.
Ethers.js
Im ersten Abschnitt des Skripts können verschiedene Netzwerke mit einem Namen, einer RPC-URL (erforderlich) und einer Chain-ID angegeben werden. Der Provider (ähnlich der web3
Instanz) wird mit der Funktion ethers.providers.StaticJsonRpcProvider
erstellt. Eine Alternative: die Funktion ethers.providers.JsonRpcProvide(providerRPC)
zu verwenden, die nur die RPC-endpoint address des Anbieters erfordert. Dies kann jedoch zu Kompatibilitätsproblemen mit einzelnen Projektspezifikationen führen.
Private key wird definiert, um eine Wallet-Instanz zu erstellen, die auch den Anbieter aus dem vorherigen Schritt benötigt. Die Wallet-Instanz wird verwendet, um Transaktionen zu signieren. Außerdem werden der Bytecode und die Schnittstelle (ABI) des Contracts aus dem Export der Kompilierung abgerufen.
Im zweiten Abschnitt wird mit ethers.ContractFactory()
eine Contractinstanz erstellt, die ABI, Bytecode und Wallet bereitstellt. Somit hat die Contractinstanz bereits einen Unterzeichner (signer). Als nächstes wird die Funktion deploy
verwendet, die die Eingabeargumente des Konstruktors benötigt. Dadurch wird die Transaktion zur contract deployment gesendet. Um auf eine Transaktionsbestätigung zu warten, können Sie die Methode deployed()
verwenden.
Die Adresse des Contracts wird im Terminal angezeigt.
Web3.py
Im ersten Abschnitt des Skripts wird die web3
Instanz (oder der Provider) mithilfe der Web3(Web3.HTTPProvider(provider_rpc))
Methode mit dem Provider-RPC erstellt. Durch die Änderung des Anbieter-RPC können Sie auswählen, an welches Netzwerk Sie die Transaktion senden möchten.
Private key und die damit verbundene public address werden zur Signierung der Transaktion und zur Festlegung der Absenderadresse definiert.
Im zweiten Abschnitt wird mit web3.eth.contract()
eine Contractinstanz erstellt, die den, aus der Kompilierungsdatei importierten ABI und Bytecode, bereitstellt. Als Nächstes kann die Konstruktortransaktion mit der Methode constructor().buildTransaction()
der Contractinstanz erstellt werden. Beachten Sie, dass Sie innerhalb von constructor()
die Konstruktor-Eingabeargumente angeben müssen. Das Ab-Konto (the from account) muss ebenfalls angegeben werden. Die Transaktionsanzahl kann auch mit der Methode web3.eth.getTransactionCount(address)
abgerufen werden.
Die Konstruktortransaktion kann mit web3.eth.account.signTransaction()
signiert werden, wobei die Konstruktortransaktion (constructor transaction ) und private key übergeben werden.
Die unterschriebene Transaktion wird versendet und die Contract adresse im Terminal angezeigt.
Lesen aus dem Contract (Call Methods)
Call Methods sind die Art der Interaktion, die den Speicher des Contracts nicht ändert (change variables), was bedeutet, dass keine Transaktion gesendet werden muss.
Schauen wir die get.* Datei (die einfachste von allen) an, die den, im Contract gespeicherten, aktuellen Wert (current value) abruft. Sie finden den Code-Schnipsel für jede Bibliothek hier (sie wurden get.*
genannt):
Die Bereitstellungsdatei besteht aus zwei Abschnitten. Im ersten Abschnitt ("Define Provider & Variables") werden die zu verwendende Bibliothek sowie die ABI und der Bytecode des Contracts importiert. Außerdem werden der Anbieter und das Konto (provider and account) (mit dem private key) definiert. Beachten Sie, dass providerRPC
sowohl den Standard-development node RPC endpoint als auch endpoint für Moonbase Alpha hat.
Der zweite Abschnitt ("Call Function") beschreibt den eigentlichen call to the contract. Unabhängig von der Bibliothek wird eine Contractinstanz erstellt (verknüpft mit der Contractadresse), von der aus call method abgefragt wird.
Web3.js
const Web3 = require('web3'); const { abi } = require('./compile'); /* -- Define Provider & Variables -- */ // Provider const providerRPC = { development: 'http://localhost:9933', moonbase: 'https://rpc.testnet.moonbeam.network', }; const web3 = new Web3(providerRPC.development); //Change to correct network // Variables const contractAddress = 'CONTRACT-ADDRESS-HERE'; /* -- Call Function -- */ // Create Contract Instance const incrementer = new web3.eth.Contract(abi, contractAddress); const get = async () => { console.log(`Making a call to contract at address: ${contractAddress}`); // Call Contract const data = await incrementer.methods.number().call(); console.log(`The current number stored is: ${data}`); }; get();
Ethers.js
const ethers = require('ethers'); const { abi } = require('./compile'); /* -- Define Provider & Variables -- */ // Provider const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9933', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.testnet.moonbeam.network', chainId: 1287, }, }; const provider = new ethers.providers.StaticJsonRpcProvider( providerRPC.development.rpc, { chainId: providerRPC.development.chainId, name: providerRPC.development.name, } ); //Change to correct network // Variables const contractAddress = 'CONTRACT-ADDRESS-HERE'; /* -- Call Function -- */ // Create Contract Instance const incrementer = new ethers.Contract(contractAddress, abi, provider); const get = async () => { console.log(`Making a call to contract at address: ${contractAddress}`); // Call Contract const data = await incrementer.number(); console.log(`The current number stored is: ${data}`); }; get();
Web3.py
from compile import abi, bytecode from web3 import Web3 # # -- Define Provider & Variables -- # # Provider provider_rpc = { 'development': 'http://localhost:9933', 'alphanet': 'https://rpc.testnet.moonbeam.network', } web3 = Web3(Web3.HTTPProvider(provider_rpc["development"])) # Change to correct network # Variables contract_address = 'CONTRACT-ADDRESS-HERE' # # -- Call Function -- # print(f'Making a call to contract at address: { contract_address }') # Create Contract Instance Incrementer = web3.eth.contract(address=contract_address, abi=abi) # Call Contract number = Incrementer.functions.number().call() print(f'The current number stored is: { number } ')
Web3.js
Im ersten Abschnitt des Skripts wird die web3
Instanz (oder der Anbieter (provider)) mithilfe des Web3-Konstruktors mit dem provider RPC erstellt. Indem Sie den Provider-RPC ändern, der dem Konstruktor übergeben wurde, können Sie auswählen, an welches Netzwerk Sie die Transaktion senden möchten.
Die Schnittstelle (ABI) und die Contractadresse werden ebenfalls benötigt, um mit ihm zu interagieren.
Im zweiten Abschnitt wird mit web3.eth.Contract()
eine Contractinstanz erstellt, indem ABI und Adresse angegeben werden. Als nächstes kann die aufzurufende Methode mit der contract.methods.methodName(_input).call()
Funktion abgefragt werden, wobei contract
, methodName
und _input
durch die Contractinstanz, die aufzurufende Funktion und die Eingabe der Funktion (falls erforderlich) ersetzt werden. Dies gibt, wenn es aufgelöst wird, den angeforderten Wert zurück.
Zuletzt wird der Wert im Terminal angezeigt.
Ethers.js
Im ersten Abschnitt des Skripts können verschiedene Netzwerke mit einem Namen, einer RPC-URL (erforderlich) und einer Chain-ID angegeben werden. Der Provider (ähnlich der web3
Instanz) wird mit der Funktion ethers.providers.StaticJsonRpcProvider
erstellt. Eine Alternative: die Funktion ethers.providers.JsonRpcProvide(providerRPC)
zu verwenden, die nur die RPC-endpoint address des Anbieters erfordert. Dies kann jedoch zu Kompatibilitätsproblemen mit einzelnen Projektspezifikationen führen.
Die Schnittstelle (ABI) und die Contractadresse werden ebenfalls benötigt, um mit ihm zu interagieren.
Im zweiten Abschnitt wird mit ethers.Contract()
eine Contractinstanz erstellt, die ihre Adresse, ABI und den Provider bereitstellt. Als nächstes kann die aufzurufende Methode mit der contract.methodName(_input)
Funktion abgefragt werden, wobei contract
, methodName
und _input
durch die Contractinstanz, die aufzurufende Funktion und die Eingabe der Funktion (falls erforderlich) ersetzt werden. Dieses Promise gibt, wenn es aufgelöst wird, den angeforderten Wert zurück.
Zuletzt wird der Wert im Terminal angezeigt.
Web3.py
Im ersten Abschnitt des Skripts wird die web3
Instanz (oder der Provider) mithilfe der Web3(Web3.HTTPProvider(provider_rpc))
Methode mit dem Provider-RPC erstellt. Durch die Änderung des Anbieter-RPC können Sie auswählen, an welches Netzwerk Sie die Transaktion senden möchten.
Die Schnittstelle (ABI) und die Contractadresse werden ebenfalls benötigt, um mit ihm zu interagieren.
Im zweiten Abschnitt wird mit web3.eth.contract()
eine Contractinstanz erstellt, indem ABI und Adresse angegeben werden. Als nächstes kann die aufzurufende Methode mit der contract.functions.method_name(input).call()
Funktion abgefragt werden, wobeicontract
, method_name
und input
durch die Contractinstanz, die aufzurufende Funktion und die Eingabe der Funktion (falls erforderlich) ersetzt werden. Dies gibt, wenn es aufgelöst wird, den angeforderten Wert zurück.
Zuletzt wird der Wert im Terminal angezeigt.
Interaktion mit dem Contract (Sendemethoden / Send Methods)
Sendemethoden sind die Art der Interaktion, die den Speicher des Contracts (change variables) ändert, was bedeutet, dass eine Transaktion signiert und gesendet werden muss.
Schauen wir die increment.* Datei an, die die, im Contract gespeicherte, Zahl um einen bestimmten Wert erhöht. Sie finden den Code-Schnipsel für jede Bibliothek hier (sie wurden increment.*
genannt):
- Web3.js: increment.js
- Ethers.js: increment.js
- Web3.py: increment.py
Die Inkrementdatei besteht aus zwei Abschnitten. Im ersten Abschnitt ("Define Provider & Variables") werden die zu verwendende Bibliothek sowie die ABI des Contracts importiert. Außerdem werden der Anbieter, die Contractadresse und der Wert derincrement
Funktion definiert. Beachten Sie, dass providerRPC
sowohl den Standard-development node RPC endpoint als auch endpoint für Moonbase Alpha hat.
Der zweite Abschnitt ("Send Function") beschreibt die eigentliche Funktion, die mit der Transaktion aufgerufen werden soll. Unabhängig von der Bibliothek wird eine Contractinstanz erstellt (verknüpft mit der Contractadresse), von der aus die zu verwendende Funktion abgefragt wird.
Web3.js
const Web3 = require('web3'); const { abi } = require('./compile'); /* -- Define Provider & Variables -- */ // Provider const providerRPC = { development: 'http://localhost:9933', moonbase: 'https://rpc.testnet.moonbeam.network', }; const web3 = new Web3(providerRPC.development); //Change to correct network // Variables const account_from = { privateKey: 'YOUR-PRIVATE-KEY-HERE', }; const contractAddress = 'CONTRACT-ADDRESS-HERE'; const _value = 3; /* -- Send Function -- */ // Create Contract Instance const incrementer = new web3.eth.Contract(abi, contractAddress); // Build Increment Tx const incrementTx = incrementer.methods.increment(_value); const increment = async () => { console.log( `Calling the increment by ${_value} function in contract at address: ${contractAddress}` ); // Sign Tx with PK const createTransaction = await web3.eth.accounts.signTransaction( { to: contractAddress, data: incrementTx.encodeABI(), gas: await incrementTx.estimateGas(), }, account_from.privateKey ); // Send Tx and Wait for Receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log(`Tx successful with hash: ${createReceipt.transactionHash}`); }; increment();
Ethers.js
const ethers = require('ethers'); const { abi } = require('./compile'); /* -- Define Provider & Variables -- */ // Provider const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9933', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.testnet.moonbeam.network', chainId: 1287, }, }; const provider = new ethers.providers.StaticJsonRpcProvider( providerRPC.development.rpc, { chainId: providerRPC.development.chainId, name: providerRPC.development.name, } ); //Change to correct network // Variables const account_from = { privateKey: 'YOUR-PRIVATE-KEY-HERE', }; const contractAddress = 'CONTRACT-ADDRESS-HERE'; const _value = 3; // Create Wallet let wallet = new ethers.Wallet(account_from.privateKey, provider); /* -- Send Function -- */ // Create Contract Instance with Signer const incrementer = new ethers.Contract(contractAddress, abi, wallet); const increment = async () => { console.log( `Calling the increment by ${_value} function in contract at address: ${contractAddress}` ); // Sign-Send Tx and Wait for Receipt const createReceipt = await incrementer.increment([_value]); await createReceipt.wait(); console.log(`Tx successful with hash: ${createReceipt.hash}`); }; increment();
Web3.py
from compile import abi, bytecode from web3 import Web3 # # -- Define Provider & Variables -- # # Provider provider_rpc = { 'development': 'http://localhost:9933', 'alphanet': 'https://rpc.testnet.moonbeam.network', } web3 = Web3(Web3.HTTPProvider(provider_rpc["development"])) # Change to correct network # Variables account_from = { 'private_key': 'YOUR-PRIVATE-KEY-HERE', 'address': 'PUBLIC-ADDRESS-OF-PK-HERE', } contract_address = 'CONTRACT-ADDRESS-HERE' value = 3 # # -- Send Function -- # print( f'Calling the increment by { value } function in contract at address: { contract_address }' ) # Create Contract Instance Incrementer = web3.eth.contract(address=contract_address, abi=abi) # Build Increment Tx increment_tx = Incrementer.functions.increment(value).buildTransaction( { 'from': account_from['address'], 'nonce': web3.eth.getTransactionCount(account_from['address']), } ) # Sign Tx with PK tx_create = web3.eth.account.signTransaction(increment_tx, account_from['private_key']) # Send Tx and Wait for Receipt tx_hash = web3.eth.sendRawTransaction(tx_create.rawTransaction) tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash) print(f'Tx successful with hash: { tx_receipt.transactionHash.hex() }')
Die zweite Datei, die mit dem Contract interagiert, ist die reset.* Datei , die die, im Vertrag gespeicherte, Zahl auf Null zurücksetzt. Den Codeausschnitt für jede Bibliothek finden Sie hier (sie wurden reset.*
genannt):
Die Struktur jeder Datei ist ihrem Inkrement.* für jede Bibliothek sehr ähnlich. Der Hauptunterschied ist die aufgerufene Methode.
Web3.js
const Web3 = require('web3'); const { abi } = require('./compile'); /* -- Define Provider & Variables -- */ // Provider const providerRPC = { development: 'http://localhost:9933', moonbase: 'https://rpc.testnet.moonbeam.network', }; const web3 = new Web3(providerRPC.development); //Change to correct network // Variables const account_from = { privateKey: 'YOUR-PRIVATE-KEY-HERE', }; const contractAddress = 'CONTRACT-ADDRESS-HERE'; /* -- Send Function -- */ // Create Contract Instance const incrementer = new web3.eth.Contract(abi, contractAddress); // Build Reset Tx const resetTx = incrementer.methods.reset(); const reset = async () => { console.log( `Calling the reset function in contract at address: ${contractAddress}` ); // Sign Tx with PK const createTransaction = await web3.eth.accounts.signTransaction( { to: contractAddress, data: resetTx.encodeABI(), gas: await resetTx.estimateGas(), }, account_from.privateKey ); // Send Tx and Wait for Receipt const createReceipt = await web3.eth.sendSignedTransaction( createTransaction.rawTransaction ); console.log(`Tx successful with hash: ${createReceipt.transactionHash}`); }; reset();
Ethers.js
const ethers = require('ethers'); const { abi } = require('./compile'); /* -- Define Provider & Variables -- */ // Provider const providerRPC = { development: { name: 'moonbeam-development', rpc: 'http://localhost:9933', chainId: 1281, }, moonbase: { name: 'moonbase-alpha', rpc: 'https://rpc.testnet.moonbeam.network', chainId: 1287, }, }; const provider = new ethers.providers.StaticJsonRpcProvider( providerRPC.development.rpc, { chainId: providerRPC.development.chainId, name: providerRPC.development.name, } ); //Change to correct network // Variables const account_from = { privateKey: 'YOUR-PRIVATE-KEY-HERE', }; const contractAddress = 'CONTRACT-ADDRESS-HERE'; // Create Wallet let wallet = new ethers.Wallet(account_from.privateKey, provider); /* -- Send Function -- */ // Create Contract Instance with Signer const incrementer = new ethers.Contract(contractAddress, abi, wallet); const reset = async () => { console.log( `Calling the reset function in contract at address: ${contractAddress}` ); // Sign-Send Tx and Wait for Receipt const createReceipt = await incrementer.reset(); await createReceipt.wait(); console.log(`Tx successful with hash: ${createReceipt.hash}`); }; reset();
Web3.py
from compile import abi, bytecode from web3 import Web3 # # -- Define Provider & Variables -- # # Provider provider_rpc = { 'development': 'http://localhost:9933', 'alphanet': 'https://rpc.testnet.moonbeam.network', } web3 = Web3(Web3.HTTPProvider(provider_rpc["development"])) # Change to correct network # Variables account_from = { 'private_key': 'YOUR-PRIVATE-KEY-HERE', 'address': 'PUBLIC-ADDRESS-OF-PK-HERE', } contract_address = 'CONTRACT-ADDRESS-HERE' # # -- Call Function -- # print(f'Calling the reset function in contract at address: { contract_address }') # Create Contract Instance Incrementer = web3.eth.contract(address=contract_address, abi=abi) # Build Reset Tx reset_tx = Incrementer.functions.reset().buildTransaction( { 'from': account_from['address'], 'nonce': web3.eth.getTransactionCount(account_from['address']), } ) # Sign Tx with PK tx_create = web3.eth.account.signTransaction(reset_tx, account_from['private_key']) # Send Tx and Wait for Receipt tx_hash = web3.eth.sendRawTransaction(tx_create.rawTransaction) tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash) print(f'Tx successful with hash: { tx_receipt.transactionHash.hex() }')
Web3.js
Im ersten Teil des Skripts (inkrement oder reset Dateien) wird die web3
Instanz (bzw. der Provider) mithilfe des Web3-Konstruktors mit dem provider RPC erstellt. Indem Sie den Provider-RPC ändern, der dem Konstruktor übergeben wurde, können Sie auswählen, an welches Netzwerk Sie die Transaktion senden möchten.
Private key und die damit verbundene public address werden zur Signierung der Transaktion und zur Protokollierung (logging) definiert. Es wird nur der privat key benötigt. Außerdem werden die Schnittstelle (ABI) und die Adresse des Contracts benötigt, um damit zu interagieren. Bei Bedarf können Sie eine beliebige Variable definieren, die als Eingabe für die Funktion erforderlich ist, mit der Sie interagieren möchten.
Im zweiten Abschnitt wird mit web3.eth.Contract()
eine Contractinstanz erstellt, indem ABI und Adresse angegeben werden. Als nächstes kann das Transaktionsobjekt mit der contract.methods.methodName(_input)
Funktion erstellen, wobei Sie contract
, methodName
und _input
durch die Contractinstanz, die aufzurufende Funktion und die Eingabe der Funktion (falls erforderlich) ersetzt werden.
Anschließend kann die Transaktion mit der web3.eth.accounts.signTransaction()
Methode signiert werden. Das Datenfeld entspricht dem Transaktionsobjekt aus dem vorherigen Schritt. Beachten Sie, dass der Wert von Gas mit der Option estimateGas()
im Transaktionsobjekt ermittelt wird.
Die signierte Transaktion wird gesendet und der Transaktions-Hash wird im Terminal angezeigt.
Ethers.js
Im ersten Teil des Skripts (inkrement oder reset Dateien) können verschiedene Netzwerke mit einem Namen, einer RPC-URL (erforderlich) und einer Chain-ID angegeben werden. Der Provider (ähnlich der web3
Instanz) wird mit der ethers.providers.StaticJsonRpcProvider
Methode erstellt. Eine Alternative: die ethers.providers.JsonRpcProvide(providerRPC)
Methode zu verwenden, die nur die RPC-endpointadresse des Anbieters erfordert.Dies kann jedoch zu Kompatibilitätsproblemen mit einzelnen Projektspezifikationen führen.
Private key wird definiert, um eine Wallet-Instanz zu erstellen, die auch den Anbieter aus dem vorherigen Schritt benötigt. Die Wallet-Instanz wird verwendet, um Transaktionen zu signieren. Außerdem werden die Schnittstelle (ABI) und die Adresse des Contracts benötigt, um damit zu interagieren. Bei Bedarf können Sie eine beliebige Variable definieren, die als Eingabe für die Funktion erforderlich ist, mit der Sie interagieren möchten.
Im zweiten Abschnitt wird mit eth.Contract()
eine Contractinstanz erstellt, die Adresse, ABI und Wallet bereitstellt. Somit hat die Contractinstanz bereits einen Unterzeichner (a signer). Als nächstes kann eine Transaktion, die einer bestimmten Funktion entspricht, mit der contract.methodName(_input)
Funktion gesendet werden, wobei Sie contract
, methodName
und _input
durch die Contractinstanz, die aufzurufende Funktion und die Eingabe der Funktion (falls erforderlich) ersetzt werden. Um auf einen Transaktionseingang zu warten, können Sie die wait()
Methode der verwenden.
Anschließend wird der Transaktions-Hash im Terminal angezeigt.
Web3.py
Im ersten Teil des Skripts (inkrement oder reset Dateien) wird die web3
Instanz (bzw. der Provider) mit der Web3(Web3.HTTPProvider(provider_rpc))
Methode mit dem Provider-RPC erstellt. Durch Änderung des Anbieter-RPC können Sie auswählen, an welches Netzwerk Sie die Transaktion senden möchten.
Private key und die damit verbundene public address werden zur Signierung der Transaktion und zur Festlegung der Absenderadresse definiert. Außerdem werden die Schnittstelle (ABI) und die Adresse des Contracts benötigt, um damit zu interagieren.
Im zweiten Abschnitt wird mit web3.eth.contract()
eine Contractinstanz erstellt, indem ABI und Adresse angegeben werden. Als Nächstes können Sie das Transaktionsobjekt mit der contract.functions.methodName(_input).buildTransaction
Funktion erstellen, wobei Sie contract
, methodName
und _input
durch die Contractinstanz, die aufzurufende Funktion und die Eingabe der Funktion (falls erforderlich) ersetzen. Innerhalb von buildTransaction() muss das From-Konto umrissen werden. Die Transaktionsanzahl kann auch mit der web3.eth.getTransactionCount(address)
Methode abgerufen werden.
Die Transaktion kann mit web3.eth.account.signTransaction()
signiert werden, wobei das Transaktionsobjekt des vorherigen Schritts und der privat key übergeben werden.
Anschließend wird der Transaktions-Hash im Terminal angezeigt.
Ausführung der Skripte
Für diesen Abschnitt wurde der zuvor gezeigte Code so angepasst, dass er für die Ausführung des development node verwendet werden kann. Bitte, dieser Anleitung folgen. Außerdem wurde jede Transaktion von dem vorfinanzierten Konto (pre-funded account) gesendet, das mit dem Noden geliefert wird:
- Private key:
99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342
- Public address:
0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b
Stellen (deploy) Sie zunächst den Contract bereit, indem Sie ihn ausführen (beachten Sie, dass das Verzeichnis für jede Bibliothek umbenannt wurde):
Web3.js
node deploy.js
Ethers.js
node deploy.js
Web3.py
python3 deploy.py
Dadurch wird der Vertrag bereitgestellt und die Adresse zurückgesendet:
Web3.js
Ethers.js
Web3.py
Führen Sie als Nächstes die Inkrementierungsdatei aus. Sie können die get-Datei verwenden, um den Wert der im Contract gespeicherten Zahl vor und nach der Erhöhung zu überprüfen:
Web3.js
# Get value node get.js # Increment value increment.js # Get value node get.js
Ethers.js
# Get value node get.js # Increment value increment.js # Get value node get.js
Web3.py
# Get value python3 get.py # Increment value python3 increment.py # Get value python3 get.py
Dies zeigt den Wert vor der Erhöhungstransaktion, den Hash der Transaktion und den Wert danach an:
Web3.js
Ethers.js
Web3.py
Führen Sie abschließend die reset-Datei aus. Auch hier können Sie mit der get-Datei den Wert der im Vertrag hinterlegten Nummer vor und nach dem Zurücksetzen überprüfen:
Web3.js
# Get value node get.js # Reset value node reset.js # Get value node get.js
Ethers.js
# Get value node get.js # Reset value node reset.js # Get value node get.js
Web3.py
# Get value python3 get.py # Reset value python3 reset.py # Get value python3 get.py
Dies zeigt den Wert vor der zurückgesetzten Transaktion, den Hash der Transaktion und den Wert danach an:
Web3.js
Ethers.js
Web3.py