Ethereum: Dynamically deploying smart contract using Web3j

Pooja Kamat
3 min readDec 20, 2023

While there are many development environments out there which can be used to deploy and test smart contract, how convenient would it be to deploy smart contract directly through your code, just like having another API which does it.

There’s already a great blog out there which helps us in setting up basic springboot project and deploying smart contract using web3j.

Here it is — SmartContract deployment & integration with JAVA SpringBoot | by Sourabh Parsekar | CoinsBench

So, what do I have in addition? the existing blog is very helpful when we want to and know which particular contract is to be deployed, so just thought of trying out what would it take to deploy any particular contract placed at a particular location?

Let's get going and see how we can do this, and how a few manual steps can be skipped and performed via code itself.

Once you have followed the referenced blog, you will have the basic code ready.

Let's walk through the changes.

To start with:

Set the solidity file location, this is the location from where we will pick the solidity files.

Make sure that you only have one contract at a time, else deployment will fail.

//location of files where the solidity files should reside before proceeding
//Here the location is read from properties file
String solidityFileLocation = applicationProperties.getSolidityFileLocation();

Next, we make sure that initially the directory which will hold the sol file is clear, and then copy the new sol files which are to be deployed.

FileUtils.cleanDirectory(new File(solidityFileLocation));
logger.info("Directory cleared successfully");

Path source = Path.of(deploymentData.getScFileLocation());//Path where sol files should be picked
Path destination = Path.of(solidityFileLocation);

FileUtil fileUtil = new FileUtil();
fileUtil.copyFiles(source, destination);

logger.info("Files copied to solidity folder");

Now, we need to run Gradle task to generate output files for Web3j. Let's not do it manually, will use the Gradle task executor to do so, this prevents any manual intervention in between deployment.

GradleTaskExecutor executor = new GradleTaskExecutor();
executor.executeGradleTask("generateContractWrappers", applicationProperties.getProjectDir());

Note: Create a file GradleExecutorFile.java to place the executor implementation and place the following code in it.

public class GradleTaskExecutor {
public void executeGradleTask(String taskName, String projectDir) {

GradleConnector connector = GradleConnector.newConnector();
connector.forProjectDirectory(new File(projectDir));

ProjectConnection connection = connector.connect();
try {
BuildLauncher launcher = connection.newBuild().forTasks(taskName).setStandardOutput(System.out).setStandardError(System.err);

//launcher.run();

} finally {
connection.close();
}

}
}

On successful task execution, it will generate the necessary files under build/generated/web3j folder.

Will be using Java reflection to dynamically detect the solidity class based on its name, use it cautiously:

String className = "org.web3j" +"."+ deploymentData.getAssetClassName()+ "."+ deploymentData.getAssetClassName();
Class<?> assetClass = Class.forName(className);

Generate credentials and contract gas provider :

web3j = Web3j.build(new HttpService(deploymentData.getNodeUrl()));
Credentials credentials = Credentials.create(deploymentData.getWalletPrivateKey());
logger.info("Credential generated");
ContractGasProvider contractGasProvider = Web3JUtils.getGasProvider(web3j);

Form the deployment object, which once executed successfully will return a remote call.

Object classObj = null;

Method deployMethod = assetClass.getMethod("deploy", Web3j.class, Credentials.class, ContractGasProvider.class, BigInteger.class);

deployMethod.setAccessible(true);

logger.info("Deploy method fetched");

RemoteCall deployObj = (RemoteCall) deployMethod.invoke(classObj, web3j, credentials, contractGasProvider, BigInteger.valueOf(0));

Once received invoke the send function.

Object sendResponse = deployObj.send();

Please note: At this stage we will receive transaction hash, the actual deployment confirmation will take a couple of minutes or hours— so will require an integration which will help us get the completion status.

Will have to either keep polling or add a watcher which will check on etherscan if the status has moved to complete from pending.

And that’s all! we are good to deploy

Stay tuned, next post will be on how we can check for the completion status of the deployment.

Thank You!

--

--