Skip to content

Instantly share code, notes, and snippets.

@transmissions11
Created June 5, 2023 06:57
Show Gist options
  • Save transmissions11/609125d3347d2566af210933524b4aab to your computer and use it in GitHub Desktop.
Save transmissions11/609125d3347d2566af210933524b4aab to your computer and use it in GitHub Desktop.
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
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.EthCall;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.response.PollingTransactionReceiptProcessor;
import org.web3j.tx.response.TransactionReceiptProcessor;
import org.web3j.utils.Numeric;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
/**
* This class provides an interface to interact with an Ethereum node using the Web3j library.
* It allows users to spin up a local Ethereum node, call functions on smart contracts,
* deploy contracts, and send transactions.
*/
public class ETHNode {
private Web3j web3;
/**
* @return the Web3j instance used to interact with the Ethereum node.
*/
public Web3j getWeb3() {
return web3;
}
/**
* Constructs an ETHNode instance.
*
* @param url the RPC URL of the Ethereum node to connect to.
*/
public ETHNode(String url) {
this.web3 = Web3j.build(new HttpService(url));
}
/**
* Calls a function on a smart contract and returns the decoded output.
*
* @param address the contract address.
* @param functionCall the function to call.
* @param credentials the user's credentials.
* @return a list of decoded output values.
* @throws Exception if there is an issue with the call.
*/
public List<Type> call(String address, Function functionCall, Credentials credentials) throws Exception {
// Create the transaction.
Transaction tx = Transaction.createEthCallTransaction(credentials.getAddress(), address, FunctionEncoder.encode(functionCall));
// Simulate the call on the node.
EthCall call = web3.ethCall(tx, DefaultBlockParameterName.LATEST).send();
// Decode the output and return it.
return FunctionReturnDecoder.decode(call.getValue(), functionCall.getOutputParameters());
}
/**
* Deploys a smart contract and returns its address.
*
* @param bytecode the contract bytecode.
* @param credentials the user's credentials.
* @return the contract address.
* @throws Exception if there is an issue with the deployment.
*/
public String deployContract(String bytecode, Credentials credentials) throws Exception {
// Create the transaction.
RawTransaction rawTransaction = RawTransaction.createContractTransaction(
getNonce(credentials),
getGasPrice(),
BigInteger.valueOf(10_000_000),
BigInteger.ZERO,
bytecode
);
// Send the tx.
EthSendTransaction tx = web3.ethSendRawTransaction(signTx(rawTransaction, credentials)).send();
// Wait for the tx to be mined and get the receipt.
TransactionReceipt receipt = waitForReceiptWithRetries(web3, tx);
// Check if the deployment was successful.
if (!receipt.isStatusOK()) throw new Exception("Deployment failed");
// Return the address.
return receipt.getContractAddress();
}
/**
* Sends a transaction to a smart contract.
*
* @param address the contract address.
* @param functionCall the function to call.
* @param credentials the user's credentials.
* @return the EthSendTransaction response.
* @throws Exception if there is an issue with the transaction.
*/
public EthSendTransaction sendTransaction(String address, Function functionCall, Credentials credentials) throws Exception {
// Create the transaction.
RawTransaction rawTransaction = RawTransaction.createTransaction(
getNonce(credentials),
getGasPrice(),
BigInteger.valueOf(10_000_000),
address,
BigInteger.ZERO,
FunctionEncoder.encode(functionCall)
);
// Send the tx.
return web3.ethSendRawTransaction(signTx(rawTransaction, credentials)).send();
}
// Utilities
/**
* Retrieves the current gas price.
*
* @return the gas price as a BigInteger.
* @throws IOException if there is an issue retrieving the gas price.
*/
private BigInteger getGasPrice() throws IOException {
// Retrieve the gas price from the node.
return web3.ethGasPrice().send().getGasPrice();
}
/**
* Retrieves the transaction count (nonce) for the given credentials.
*
* @param credentials the user's credentials.
* @return the transaction count as a BigInteger.
* @throws IOException if there is an issue retrieving the transaction count.
*/
private BigInteger getNonce(Credentials credentials) throws IOException {
// Retrieve the transaction count from the node.
EthGetTransactionCount ethGetTransactionCount = web3.ethGetTransactionCount(
credentials.getAddress(),
// We need to use PENDING if we're
// sending many transactions in a row.
DefaultBlockParameterName.PENDING
).send();
// Return the transaction count.
return ethGetTransactionCount.getTransactionCount();
}
/**
* Signs a raw transaction with the given credentials.
*
* @param tx the raw transaction to sign.
* @param credentials the user's credentials.
* @return the signed transaction as a hexadecimal string.
*/
private String signTx(RawTransaction tx, Credentials credentials) {
// Sign the transaction via the TransactionEncoder.
byte[] signedMessage = TransactionEncoder.signMessage(tx, credentials);
return Numeric.toHexString(signedMessage); // Convert it to a hex string.
}
/**
* Waits for a transaction receipt to be available.
*
* @param web3 the Web3j instance.
* @param tx the transaction.
* @return the transaction receipt.
* @throws Exception if there is an issue fetching the receipt.
*/
private TransactionReceipt waitForReceiptWithRetries(Web3j web3, EthSendTransaction tx) throws Exception {
TransactionReceiptProcessor receiptProcessor = new PollingTransactionReceiptProcessor(web3, 250, 60);
return receiptProcessor.waitForTransactionReceipt(tx.getTransactionHash());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment