[Ethereum] Load smart contracts in Java application without having the java wrapper class for Web3j (only the address of the contract)

contract-invocationweb3j

I use web3j to interact with my local Ethereum node (created with geth), and I was wondering how should I handle smart contracts created at runtime.

I know that in order to deploy a smart contract you have to write the source code in Solidity, compile it to obtain both abi and bin files. Then you have to generate with web3j the java class to have a representation for JVM, and be able to call MyContractClass.deploy(…).

What I want to achieve is to generate a smart contract at runtime with some custom data, deploy it and then interact with it from other instances of my Java application. The problem is that I couldn't find any management api with geth to implement some adapter, and also Web3j requires a wrapper for that contract (a java class built from abi and bin files). So the only way to load it using this library is by using the wrapper java class (e.g.: MyContract.load(address, …).

My idea is to have another SmartContract (master) which holds the addresses of all created contracts, but also the bin and abi files, so all I would have to do would be to interact with that contract and retrieve the addresses of the other ones, and then using web3j from the host machine I would generate the java class and load it using web3j. Is it bad to store abi and bin files in the smart contract?

Best Answer

Take a look at the code generated by the wrappers

Function name() for a ERC20

    public RemoteCall<String> name() {
        final Function function = new Function(FUNC_NAME, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}));
        return executeRemoteCallSingleValueReturn(function, String.class);
    }

And transferFrom() for ERC20

    public RemoteCall<TransactionReceipt> transferFrom(String _from, String _to, BigInteger _value) {
        final Function function = new Function(
                FUNC_TRANSFERFROM, 
                Arrays.<Type>asList(new org.web3j.abi.datatypes.Address(_from), 
                new org.web3j.abi.datatypes.Address(_to), 
                new org.web3j.abi.datatypes.generated.Uint256(_value)), 
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

When called it will execute a function executeRemoteCallXXXXX(function).

To construct a dynamic class you have to construct function which you pass the name of the function to invoke, a list with input parameters and a list with output parameters. See here https://github.com/web3j/web3j/blob/a0ece8b8fb76397c24592cc9d59578cdabbf751c/abi/src/main/java/org/web3j/abi/datatypes/Function.java#L17-L22.

public Function(String name, List<Type> inputParameters,
                    List<TypeReference<?>> outputParameters) {
        this.name = name;
        this.inputParameters = inputParameters;
        this.outputParameters = convert(outputParameters);
}