Created
June 5, 2023 06:57
-
-
Save transmissions11/609125d3347d2566af210933524b4aab to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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