[Ethereum] Sign Message Using private key instead of kesytore

ethereumjsweb3js

I need to sign data using the private key and not keystore file. I can get data using:

var hash = "0x" + ethereumjs.ABI.soliditySHA3(
    ["address", "uint256", "uint256"],
    [web3.eth.defaultAccount, amount, nonce]
  ).toString("hex");

and sign the data using:

web3.personal.sign(hash, web3.eth.defaultAccount, callback);

But I am not sure how can sign this message using private key and without use of unlocking the account.

I am not willing not use personal over RPC calls.

Best Answer

Try these three functions:

async function executeTransaction(transaction, value = 0) {
    return await signAndSendTransaction(transaction._parent._address, transaction.encodeABI(), value, 0);
}

async function transferEtherToContract(address, value) {
    return await signAndSendTransaction(address, "", value, 0);
}

async function transferEtherToAccount(address, value) {
    return await signAndSendTransaction(address, "", value, 21000);
}

All of which rely on this function:

async function signAndSendTransaction(to, data, value, gas) {
    while (true) {
        try {
            let options = {
                to   : to,
                data : data,
                value: value
            };
            options.gas = gas ? gas : (await web3.eth.getBlock("latest")).gasLimit;
            const signedTransaction  = await web3.eth.accounts.signTransaction(options, PRIVATE_KEY);
            const transactionReceipt = await web3.eth.sendSignedTransaction(signedTransaction.rawTransaction);
            return transactionReceipt;
        }
        catch (error) {
            console.log(error.message);
            console.log("Press enter to try again...");
            await new Promise(function(resolve, reject) {
                process.stdin.resume();
                process.stdin.once("data", function(data) {
                    process.stdin.pause();
                    resolve();
                });
            });
        }
    }
}

Note that in web3.js v1.0.0-beta.34 or earlier (and possibly later as well), function web3.eth.accounts.signTransaction may change the values in the options object passed to it.

They've fixed it at some point (via deep-cloning of this object), but I'm not sure which version.

Therefore, we initialize a new options object at every iteration.

In addition, since the latest block's gas-limit may change, we fetch it too at every iteration.

Related Topic