Moonbeam
July 22, 2021

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 constructorFunktion, die ausgeführt wird, wenn der Contract bereitgestellt wird, legt den Anfangswert der on-chain gespeicherten Zahlenvariablen fest (Standardwert ist 0). DieincrementFunktion 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 resetFunktion 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):

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 IncrementerContracts 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_fileskompiliert. 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 Solcinstalliert 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 web3Instanz (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 web3Instanz) 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 web3Instanz) 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 inputdurch 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):

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 derincrementFunktion 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 web3Instanz) 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

Original (engl.)