Ethereum smart contract interactive call, web3.js, web3j two ways to achieve

Introduction

Continuing from the previous article "Using hardhat to deploy solidity smart contracts to the testnet"
After deploying the contract, how to interact with the blockchain? The main content of this section is to use web3.js and web3j to interact with the blockchain and the contracts on the chain. Among them, web3.js belongs to the javascript version,
and web3j belongs to the java version.

Types of Contract Interactions

Ethereum can be regarded as a public database, which provides read and write functions, but cannot be deleted.
Initiating a transaction is actually writing the transaction to the database. Writing to the database cannot be done in vain. If other nodes record the data for you, you have to pay some fees to the nodes that help you record it. This fee is the gas we often see. Therefore, all operations on Ethereum that change data on the chain cost gas , while reading is free.
We can simply divide the types of contract transactions into three types:
1. Read-only calls
2. Calls to pay gas
3. Calls to pay gas and value

1 and 2 have been mentioned above, so what is the third. The third case is to transfer the ETH to the contract when calling the contract. This value is the value of the transfer, and the contract can accept ETH. If you want the contract to receive ETH, add the payable
keyword statement to the calling method . In addition, the contract must also declare a receive() method, indicating that the contract can receive ETH. In solidity 0.6.10, it is receive, which is different The declaration of the version of the method may differ.

receive() payable external {}

Closer to home, let’s get down to business

Interact with contracts using web3.js

Introduce web3.js in the project

npm install web3

project skeleton

	var Web3 = require('web3');
	var web3 = new Web3("https://rinkeby.infura.io/v3/7d00bf84530c4264969a4f0f231de8b6");
	var privateKey = "私钥";
	var contractAbi = [{
    
    "inputs":[],"name":"getBalance","outputs":[{
    
    "internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{
    
    "inputs":[],"name":"getName","outputs":[{
    
    "internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{
    
    "inputs":[],"name":"name","outputs":[{
    
    "internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{
    
    "inputs":[],"name":"payETH","outputs":[],"stateMutability":"payable","type":"function"},{
    
    "inputs":[{
    
    "internalType":"string","name":"_name","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{
    
    "stateMutability":"payable","type":"receive"}];
	var contractAddress = "0xb19c13d0A37cDDE5c1F969a0d9BD6a50B3A11B4E"
	var hello = new web3.eth.Contract(contractAbi, contractAddress);
	
	main()
	  .then(() => process.exit(0))
	  .catch(error => {
    
    
	    console.error(error);
	    process.exit(1);
	  });
	
	
	async function main(){
    
    
	  await getName();
	  
	}
	async function getName(){
    
    
	  var name = await hello.methods.getName().call();
	  console.log(name);
	}

read-only call

	async function getName(){
    
    
	  var name = await hello.methods.getName().call();
	  console.log(name);
	}
	
	async function getBalance(){
    
    
	  var balance = await hello.methods.getBalance().call();
	  console.log("balance = "+balance);
	}

Call to pay gas

	async function setName(){
    
    
	  var name = "Jack";
	  var functionEncode = await hello.methods.setName(name).encodeABI();
	  var sign = await web3.eth.accounts.signTransaction({
    
    
	    gas: 300000,
	    to: contractAddress,
	    data: functionEncode,
	   }, privateKey);
	   var result = await web3.eth.sendSignedTransaction(sign.rawTransaction);
	  console.log("setName txHash = "+result.transactionHash);
	}

Call to pay gas and value

	async function reviceETH(){
    
    
	   var ethValue = 100;
	   var functionEncode = await hello.methods.reviceETH().encodeABI();
	   var sign = await web3.eth.accounts.signTransaction({
    
    
	     gas: 300000, 
	     to: contractAddress,
	     data: functionEncode,
	     value: ethValue
	    }, privateKey);
	    var result = await web3.eth.sendSignedTransaction(sign.rawTransaction);
	    console.log("reviceETH resultTxHash = "+result.transactionHash);
	}

Results of the
insert image description here

Interact with contracts using web3j

The maven project is used here, the first step is to introduce the web3j package

import pom

     <dependency>
            <groupId>org.web3j</groupId>
            <artifactId>core</artifactId>
            <version>3.4.0</version>
        </dependency>

the code

The Java version directly uploads the code, which is the call of the above three methods


import org.junit.Test;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.*;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class We3jTest2 {
    
    

	public static String node = "https://rinkeby.infura.io/v3/7d00bf84530c4264969a4f0f231de8b6";
	Web3j web3j;
	Credentials credentials;
	{
    
    
		web3j = Web3j.build(new HttpService(node));
		credentials = Credentials.create("私钥");
	}

	public static final String contractAddress = "0xb19c13d0A37cDDE5c1F969a0d9BD6a50B3A11B4E";


	/**
	 * 调用合约的只读方法,无需gas
	 * @throws Exception
	 */
	@Test
	public void getName() throws Exception {
    
    
		Function function = new Function(
				"getName",
				Collections.emptyList(),
				Arrays.asList(new TypeReference<Utf8String>(){
    
    }));

		String encodedFunction = FunctionEncoder.encode(function);
		org.web3j.protocol.core.methods.response.EthCall response = web3j.ethCall(
				Transaction.createEthCallTransaction(null, contractAddress, encodedFunction),
				DefaultBlockParameterName.LATEST)
				.sendAsync().get();

		List<Type> results = FunctionReturnDecoder.decode(response.getValue(), function.getOutputParameters());
		Utf8String preValue = (Utf8String)results.get(0);
		System.out.println(preValue.getValue());
	}

	/**
	 * 需要支付gas的方法
	 * @throws Exception
	 */
	@Test
	public void setName() throws Exception {
    
    
		Function function = new Function(
				"setName",
				Arrays.asList(new Utf8String("Tom")),
				Collections.emptyList());
		BigInteger nonce = getNonce(credentials.getAddress());
		String encodedFunction = FunctionEncoder.encode(function);

		BigInteger gasLimit = new BigInteger("300000");
		RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, DefaultGasProvider.GAS_PRICE,gasLimit, contractAddress, encodedFunction);

		org.web3j.protocol.core.methods.response.EthSendTransaction response =
				web3j.ethSendRawTransaction(Numeric.toHexString(TransactionEncoder.signMessage(rawTransaction, credentials)))
						.sendAsync()
						.get();

		String transactionHash = response.getTransactionHash();
		System.out.println(transactionHash);
	}

	/**
	 * 需要支付gas和value的合约方法调用
	 * @throws Exception
	 */
	@Test
	public void payETH() throws Exception {
    
    
		BigInteger nonce = getNonce(credentials.getAddress());
		Function function = new Function("payETH",
				Collections.EMPTY_LIST,
				Collections.EMPTY_LIST);

		String functionEncode = FunctionEncoder.encode(function);
		BigInteger value = new BigInteger("200");
		// 与不需要支付的value的方法调用,差别就在于多传一个eth数量的value参数
		RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, DefaultGasProvider.GAS_PRICE,DefaultGasProvider.GAS_LIMIT, contractAddress, value,functionEncode);
		org.web3j.protocol.core.methods.response.EthSendTransaction response =
				web3j.ethSendRawTransaction(Numeric.toHexString(TransactionEncoder.signMessage(rawTransaction, credentials)))
						.sendAsync()
						.get();
		String transactionHash = response.getTransactionHash();
		System.out.println(transactionHash);
	}


	private BigInteger getNonce(String address) throws Exception {
    
    
		EthGetTransactionCount ethGetTransactionCount =
				web3j.ethGetTransactionCount(address, DefaultBlockParameterName.LATEST)
						.sendAsync()
						.get();
		return ethGetTransactionCount.getTransactionCount();
	}

}

Summarize

  1. The call of the read-only contract is the call method. This method does not require a private key signature, and only needs to know the address and method (method name, input parameter, and output parameter) of the contract.
  2. The payment of gas and the call with value all require the signature of the account private key, which is divided into three steps: encode (method encoding), sign (sign the method), and send (send the signed transaction).
  3. Regardless of js and java, the calling process is the same, essentially calling the Ethereum node through json-rpc

The etherscan address of the contract

reference documents

web3.js Chinese documentation
web3j English documentation
web3h Chinese documentation

If there are any mistakes in the above content, please leave a message for discussion.

Replenish:

The web3j call returns the type of multiple address parameters

A friend asked me how to write the value returned by the contract as an array of addresses.
The following is an example of mine

    @Test
	public void callContractTransaction() throws Exception {
    
    
		Function function = new Function(
				"getComponents",
				Collections.EMPTY_LIST,
				Arrays.asList(new TypeReference<DynamicArray<Address>>(){
    
    }));

		String encodedFunction = FunctionEncoder.encode(function);
		org.web3j.protocol.core.methods.response.EthCall response = web3j.ethCall(
				Transaction.createEthCallTransaction(null, contractAddress, encodedFunction),
				DefaultBlockParameterName.LATEST)
				.sendAsync().get();
		Assert.isNull(response.getError(),"callContractTransaction error");

		List<Type> results = FunctionReturnDecoder.decode(response.getValue(), function.getOutputParameters());
		for (Type result : results) {
    
    
			System.out.println(result.getValue());
		}
	}

Guess you like

Origin blog.csdn.net/qq_36838406/article/details/118386159