There is different way to send transactions to a smart contract through node:
(1) A client signs a transaction with his account (private key) and send it to the node. Then the node only broadcasts it to the network.
Transaction fees are paid by the client.
(2) A client sends a clear transaction (no signature) and ask the node to sign and broadcast the transaction with one of the account managed by this node. That's the all concept of personal unlocked account
which should be used only for personal use or testing.
Transaction fees are paid by the node.
By doing this (below), you basically create an account directly on the node (2)
NewAccountIdentifier newAccountIdentifier = admin.personalNewAccount(key).send();
String address = newAccountIdentifier.getAccountId();
If you want to create and manage an account only on the client (java program), you would have to do this:
ECKeyPair keyPair = Keys.createEcKeyPair();
Credentials credentials = Credentials.create(privateKey);
In web3j you have the concept of TransactionManager
responsible of executing the transactions and you have different type of TransactionManager:
RawTransactionManager
can sign and send transaction (1)
ReadonlyTransactionManager
can only read data (no transaction)
ClientTransactionManager
can only send a clear transaction to the node and let the node sign it (2)
When you load the contract like you did UsersContract userContract = UsersContract.load(address, admin, credential, ...)
, behind the scene, Web3J instantiate a RawTransactionManager
which will sign the transaction (using the credentials
- private key) before sending it to the node.
UsersContract userContract = UsersContract.load("0xc85e6e4b979d05a9b5adbac3e0e7d68b632460d1", admin, credentials, new BigInteger("240000"), new BigInteger("2400000"));
But in your case, you actually need a ClientTransactionManager
, so you can directly pass it to the UsersContract.load(...)
method like this
ClientTransactionManager transactionManager = new ClientTransactionManager(web3j, newAccountIdentifier.getAccountId());
UsersContract userContract = UsersContract.load("0xc85e6e4b979d05a9b5adbac3e0e7d68b632460d1", admin, transactionManager, new BigInteger("240000"), new BigInteger("2400000"));
Best Answer
So I found a solution, and it was to change my send code to use raw transactions