L'article suivant décrit comment exécuter un contrat à l'aide de Web3j. Dans cet article, vous allez créer une classe Java pour les opérations de contrat et exécuter le contrat via cette classe.
Comment exécuter un contrat avec web3j
Avec cette méthode, à mesure que le nombre de contrats augmente, le nombre de classes Java augmente du nombre de contrats, ce qui peut être compliqué à gérer. Par conséquent, nous décrirons comment exécuter en spécifiant l'adresse du contrat et le nom de la fonction.
Le contrat émet des jetons ERC20 à l'aide d'Openzeppelin. Le contenu consiste à créer une classe qui hérite de ERC20.sol et à préparer uniquement le constructeur.
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"; //Nom du jeton
string public symbol = "ORG"; //Notation d'unité du jeton
uint public decimals = 18; //Nombre de chiffres de la virgule décimale
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);
}
}
Vient ensuite une classe Java, qui est plutôt rudimentaire. L'idée de base peut être exécutée si vous connaissez l'adresse du contrat, le nom de la fonction, les arguments et la valeur de retour. C'est fait.
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<>();
//Aucun argument / valeur de retour uint256
result = exec.execFunction("totalSupply", inputParam, ResultType.INT);
System.out.println("Total Supply : " + ((Uint)result.get(0)).getValue());
// FROM_ADRESSE et À_Confirmation du solde de ADDRESS
confirmBalance(OWNER_ADDRESS, TO_ADDRESS);
//Avec argument (adresse,uint256) / valeur de retour 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<>();
//Avec argument (adresse) / valeur de retour 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++;
}
}
/**
*Exécution de la fonction où la transaction n'a pas lieu (la valeur n'est pas mise à jour)
* @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());
}
/**
*Exécution de la fonction où la transaction se produit (la valeur est mise à jour)
* @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 {
//Obtenez une valeur nonce
EthGetTransactionCount ethTransactionCount =
web3j.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.PENDING).send();
BigInteger nonce = ethTransactionCount.getTransactionCount();
//Génération de transaction
RawTransaction rawTransaction = RawTransaction.createTransaction(
nonce,
BigInteger.valueOf(1000),
BigInteger.valueOf(4700000),
CONTRACT_ADDRESS,
encodedFunction);
//Signature
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
String hexValue = Numeric.toHexString(signedMessage);
//send
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
//Confirmation d'erreur
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
}
Ce que vous faites avec la méthode principale est simple. Vérifiez le montant des jetons émis, vérifiez le solde et envoyez de l'argent. Enfin, reconfirmez l'équilibre.
En d'autres termes, en se concentrant sur la création de contrat, c'est comme suit.
Le premier est l'exécution d'une fonction qui ne met pas à jour la valeur. Dans ERC20.sol, il y a «offre totale» et «solde de». Le code est comme suit.
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());
}
Que fais tu
Dans cet exemple de code, l'argument de «execFunction» spécifie ce que l'appelant veut que le type de retour renvoie. ResultType définit quelle classe le type défini dans solidity est traité comme un type d'énumération en Java. J'essaye de renvoyer la classe qui correspond à la valeur de retour dans la méthode "getTypeReference".
Enfin, la valeur renvoyée sous forme de données binaires est décodée et renvoyée à l'appelant.
Vient ensuite un appel de fonction avec une mise à jour de valeur. C'est assez différent de faire.
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 {
//Obtenez une valeur nonce
EthGetTransactionCount ethTransactionCount =
web3j.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.PENDING).send();
BigInteger nonce = ethTransactionCount.getTransactionCount();
//Génération de transaction
RawTransaction rawTransaction = RawTransaction.createTransaction(
nonce,
BigInteger.valueOf(1000), //GAS
BigInteger.valueOf(4700000), //GASLimit
CONTRACT_ADDRESS,
encodedFunction);
//Signature
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
String hexValue = Numeric.toHexString(signedMessage);
//send
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
//Confirmation d'erreur
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;
}
Que fais tu
Une transaction est générée car il y a une mise à jour de valeur, et la mise à jour est confirmée lorsqu'elle est prise dans le bloc. Par conséquent, la méthode d'appel est assez différente de la fonction qui ne met pas à jour la valeur.
Personnellement, j'aime créer une classe pour chaque contrat de manière intuitive, mais si vous créez un mécanisme pour appeler un contrat et obtenir une valeur, vous pouvez créer un code assez polyvalent. C'est vrai.
Recommended Posts