Der folgende Artikel beschreibt, wie Sie einen Vertrag mit Web3j ausführen. In diesem Artikel erstellen Sie eine Java-Klasse für Vertragsoperationen und führen den Vertrag über diese Klasse aus.
So führen Sie einen Vertrag mit web3j aus
Mit dieser Methode erhöht sich mit zunehmender Anzahl von Verträgen die Anzahl von Java-Klassen um die Anzahl von Verträgen, deren Verwaltung kompliziert sein kann. Daher beschreiben wir die Ausführung durch Angabe der Vertragsadresse und des Funktionsnamens.
Der Vertrag stellt ERC20-Token mit Openzeppelin aus. Der Inhalt besteht darin, eine Klasse zu erstellen, die ERC20.sol erbt, und nur den Konstruktor vorzubereiten.
MyToken.sol
pragma solidity ^0.4.24;
import "node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
string public name = "OrgToken"; //Token-Name
string public symbol = "ORG"; //Einheitennotation des Tokens
uint public decimals = 18; //Anzahl der Nachkommastellen
address public account = msg.sender;
uint256 public _totalS = 10000000000000;
constructor () public {
super._mint(account, _totalS);
}
function balanceOf(address target) public view returns (uint256) {
return super.balanceOf(target);
}
}
Als nächstes kommt eine Java-Klasse, die ziemlich grob ist. Die Grundidee kann ausgeführt werden, wenn Sie die Vertragsadresse, den Funktionsnamen, die Argumente und den Rückgabewert kennen. Es ist gemacht.
MyTokenExec.Java
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Bool;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.Uint;
import org.web3j.abi.datatypes.Utf8String;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthCall;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.http.HttpService;
import org.web3j.utils.Numeric;
public class MyContractExec {
public static final Admin web3j = Admin.build(new HttpService("http://127.0.0.1:8545"));
private static final String CONTRACT_ADDRESS = "0x715d4c293482e6f72e1cbb3b22a10fbdae3bd7b0";
public static final String OWNER_ADDRESS = "0x945cd603a6754cb13c3d61d8fe240990f86f9f8a";
public static final String TO_ADDRESS = "0x66b4e7be902300f9a15d900822bbd8803be87391";
public static void main(String args[]) {
MyContractExec exec = new MyContractExec();
List<?> result = null;
try {
List<Type> inputParam = new ArrayList<>();
//Kein Argument / Rückgabewert uint256
result = exec.execFunction("totalSupply", inputParam, ResultType.INT);
System.out.println("Total Supply : " + ((Uint)result.get(0)).getValue());
// FROM_ADRESSE und ZU_Saldobestätigung der ADRESSE
confirmBalance(OWNER_ADDRESS, TO_ADDRESS);
//Mit Argument (Adresse,uint256) / Rückgabewert bool
inputParam = new ArrayList<>();
inputParam.add(new Address(TO_ADDRESS));
inputParam.add(new Uint(BigInteger.valueOf(123456)));
result = sendSignedTransaction(credentials, "transfer", inputParam, ResultType.BOOL);
System.out.println( ((Bool)result.get(0)).getValue() );
confirmBalance(OWNER_ADDRESS, TO_ADDRESS);
}catch(IOException e) {
e.printStackTrace();
}
}
public static void confirmBalance(String ... args) throws IOException{
MyContractExec exec = new MyContractExec();
List<?> result = null;
int i = 0;
for(String address :args) {
List<Type> inputParam = new ArrayList<>();
//Mit Argument (Adresse) / Rückgabewert uint256
inputParam.add(new Address(address));
result = exec.execFunction("balanceOf", inputParam, ResultType.INT);
System.out.println("Balance of ADDRESS[" + i + "] : " + ((Uint)result.get(0)).getValue() );
i++;
}
}
/**
*Ausführung einer Funktion, die keine Transaktion generiert (keine Wertaktualisierung)
* @param functionName
* @return
* @throws IOException
*/
public List<?> execFunction(String functionName, List<Type> args, ResultType type) throws IOException{
Function function = new Function(
functionName, args, Arrays.<TypeReference<?>>asList( getTypeReference(type) ));
String encodedFunction = FunctionEncoder.encode(function);
EthCall ethCall = web3j.ethCall(
Transaction.createEthCallTransaction(
OWNER_ADDRESS, CONTRACT_ADDRESS, encodedFunction),
DefaultBlockParameterName.LATEST)
.send();
String value = ethCall.getValue();
return FunctionReturnDecoder.decode(value, function.getOutputParameters());
}
/**
*Ausführung der Funktion, bei der die Transaktion stattfindet (Wert wird aktualisiert)
* @param credentials
* @param functionName
* @param args
* @param type
* @return
*/
public static List<?> sendSignedTransaction(Credentials credentials, String functionName, List<Type> args, ResultType type){
Function function = new Function(
functionName, args, Arrays.<TypeReference<?>>asList( getTypeReference(type) ));
String encodedFunction = FunctionEncoder.encode(function);
try {
//Holen Sie sich Nonce-Wert
EthGetTransactionCount ethTransactionCount =
web3j.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.PENDING).send();
BigInteger nonce = ethTransactionCount.getTransactionCount();
//Transaktionsgenerierung
RawTransaction rawTransaction = RawTransaction.createTransaction(
nonce,
BigInteger.valueOf(1000),
BigInteger.valueOf(4700000),
CONTRACT_ADDRESS,
encodedFunction);
//Unterschrift
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
String hexValue = Numeric.toHexString(signedMessage);
//send
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
//Fehlerbestätigung
if(ethSendTransaction.getError() != null){
System.out.println(ethSendTransaction.getError().getMessage());
}else {
String value = ethSendTransaction.getResult();
return FunctionReturnDecoder.decode(value, function.getOutputParameters());
}
}catch(IOException | ExecutionException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
public static TypeReference<?> getTypeReference(ResultType type){
TypeReference<?> typeReference = null;
switch(type) {
case ADDRESS:
typeReference = new TypeReference<Address>() {};
break;
case BOOL:
typeReference = new TypeReference<Bool>() {};
break;
case STRING:
typeReference = new TypeReference<Utf8String>() {};
break;
case INT:
typeReference = new TypeReference<Uint>() {};
break;
default:
break;
}
return typeReference;
}
}
ResultType.java
public enum ResultType {
ADDRESS,
BOOL,
STRING,
INT
}
Was Sie mit der Hauptmethode machen, ist einfach. Überprüfen Sie die Anzahl der ausgegebenen Token, überprüfen Sie den Kontostand und senden Sie Geld. Bestätigen Sie abschließend den Kontostand erneut.
Mit anderen Worten, wenn man sich auf die Schaffung eines Vertrags konzentriert, ist dies wie folgt.
Die erste ist die Ausführung einer Funktion, die den Wert nicht aktualisiert. In ERC20.sol gibt es "Gesamtangebot" und "Saldo von". Der Code lautet wie folgt.
MyTokenExec.java
public List<?> execFunction(String functionName, List<Type> args, ResultType type) throws IOException{
Function function = new Function(
functionName, args, Arrays.<TypeReference<?>>asList( getTypeReference(type) ));
String encodedFunction = FunctionEncoder.encode(function);
EthCall ethCall = web3j.ethCall(
Transaction.createEthCallTransaction(
OWNER_ADDRESS, CONTRACT_ADDRESS, encodedFunction),
DefaultBlockParameterName.LATEST)
.send();
String value = ethCall.getValue();
return FunctionReturnDecoder.decode(value, function.getOutputParameters());
}
Was machst du
In diesem Beispielcode gibt das Argument "execFunction" an, was der Aufrufer vom Rückgabetyp zurückgeben möchte. ResultType definiert, welche Klasse der in Solidität festgelegte Typ in Java als Aufzählungstyp behandelt wird. Ich versuche, die Klasse zurückzugeben, die dem Rückgabewert in der Methode "getTypeReference" entspricht.
Schließlich wird der als Binärdaten zurückgegebene Wert dekodiert und an den Aufrufer zurückgegeben.
Als nächstes folgt ein Funktionsaufruf mit einer Wertaktualisierung. Das ist ganz anders.
MyTokenExec.java
public static List<?> sendSignedTransaction(Credentials credentials, String functionName, List<Type> args, ResultType type){
Function function = new Function(
functionName, args, Arrays.<TypeReference<?>>asList( getTypeReference(type) ));
String encodedFunction = FunctionEncoder.encode(function);
try {
//Holen Sie sich Nonce-Wert
EthGetTransactionCount ethTransactionCount =
web3j.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.PENDING).send();
BigInteger nonce = ethTransactionCount.getTransactionCount();
//Transaktionsgenerierung
RawTransaction rawTransaction = RawTransaction.createTransaction(
nonce,
BigInteger.valueOf(1000), //GAS
BigInteger.valueOf(4700000), //GASLimit
CONTRACT_ADDRESS,
encodedFunction);
//Unterschrift
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
String hexValue = Numeric.toHexString(signedMessage);
//send
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
//Fehlerbestätigung
if(ethSendTransaction.getError() != null){
System.out.println(ethSendTransaction.getError().getMessage());
}else {
String value = ethSendTransaction.getResult();
return FunctionReturnDecoder.decode(value, function.getOutputParameters());
}
}catch(IOException | ExecutionException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
Was machst du
Eine Transaktion wird generiert, weil eine Wertaktualisierung vorliegt, und die Aktualisierung wird bestätigt, wenn sie in den Block aufgenommen wird. Daher unterscheidet sich die aufrufende Methode erheblich von der Funktion, die den Wert nicht aktualisiert.
Ich persönlich mag es, intuitiv eine Klasse für jeden Vertrag zu erstellen, aber wenn Sie einen Mechanismus erstellen, um einen Vertrag aufzurufen und einen Wert zu erhalten, können Sie einen Code erstellen, der sehr vielseitig ist. Korrekt.
Recommended Posts