23

This question is related to this one and this one. It also has a partial answer here and here.

In the third link the account is being unlocked for a period of time using web3.js:

web3.personal.unlockAccount("0x..", "<passs>", 1000);

The unlock period parameter is optional.

How is it possible to check if accounts are locked (prior to making transactions)?

Are there any functionality consequences of unlocking an already unlocked account?

3
  • Is <pass> the private key? E.g. let account = self.web3.eth.accounts.privateKeyToAccount(self.config.walletPrivateKey); & self.web3.eth.personal.unlockAccount(account.address, account.privateKey, 200)
    – Andi Giga
    Commented Nov 29, 2017 at 8:58
  • No, just a password used to encrypt the private key (that is later used in transactions).
    – Sebi
    Commented Nov 30, 2017 at 11:10
  • 1
    Note that the personal API is legacy and no wallet in practice use this. Different wallets provide different providers to sign transactions. More information here: ethereum.stackexchange.com/questions/82531/… Commented Sep 22, 2020 at 7:27

4 Answers 4

10

There currently isn't a method for checking whether an account is locked or not in the web3 JS API.

However, from the code, if an account is already unlocked, then there's no problem calling unlock again.

// If the account address is already unlocked for a duration, TimedUnlock extends or
// shortens the active unlock timeout. If the address was previously unlocked
// indefinitely the timeout is not altered.
func (am *Manager) TimedUnlock(a Account, passphrase string, timeout time.Duration) error {

Why are we only looking at TimedUnlock(), which presumably only gets invoked if we pass the third parameter?

As you noted, the unlock period parameter is optional. If it isn't provided, then we call Unlock(), which is a wrapper around TimedUnlock(), but which passes 0 as the time period. Hence we only need consider the TimedUnlock() function in the explanation.

2
  • I have a design that may change and do not know yet which choice is best. I'll go with no time unlock for now (this would normally keep the account unlocked indefinitely).
    – Sebi
    Commented Jul 9, 2016 at 21:28
  • I'd argue that there is a problem in unlocking an account over and over again and that is that the unlocking takes quite some time (~3s for me using latest geth).
    – SCBuergel
    Commented Jan 19, 2017 at 13:04
8

Here is a workaround to check if account is unlocked. It is not very beautiful but in most cases it works. Use it only for development purposes on testnet or private net!!! Because "this sends out an actual transaction for which you have to pay gas" Unlocking accounts and making transactions in web3.js

function isAccountLocked(account) {
    try {
        web3.eth.sendTransaction({
            from: account,
            to: account,
            value: 0
        });
        return false;
    } catch (err) {
        return (err.message == "authentication needed: password or unlock");
    }
}

function unlockAccountsIfNeeded(accounts, passwords, unlock_duration_sec) {
    if (typeof(unlock_duration_sec)==='undefined') unlock_duration_sec = 300;

    for (let i = 0; i < accounts.length; i++) {
        if (isAccountLocked(accounts[i])) {
            console.log("Account " + accounts[i] + " is locked. Unlocking")
            web3.personal.unlockAccount(accounts[i], passwords[i], unlock_duration_sec);
        }
    }
}
2
  • 4
    This is indeed not very beautiful because this sends out an actual transaction for which you have to pay gas.
    – SCBuergel
    Commented Feb 24, 2017 at 14:18
  • 1
    @AlexeyBarsuk nice script, i suggest to add unlock duration (0 unlocked as geth is running) web3.personal.unlockAccount(accounts[i], passwords[i], Duration);
    – Badr Bellaj
    Commented Nov 2, 2017 at 22:35
7

You can use web3.eth.sign and check if it fails.

async function isUnlocked (web3, address) {
    try {
        await web3.eth.sign("", address);
    } catch (e) {
        return false;
    }
    return true;
}
2
  • Please give a little more detail in your answer. Providing a link without much context may not help the OP.
    – Malone
    Commented Nov 10, 2017 at 13:46
  • @Malone web3.eth.sign will throw "authentication needed: password or unlock" in case you are not unlocked
    – kroe
    Commented Jul 4, 2018 at 4:46
0

This is a possible method, directly calling the JSON RPC method personal_listWallets:

async function listWallets() {
    try {
        const result = await sendRPC_personal_listWallets();
        console.log(typeof result);
        return result;
    } catch (e) {
        return e;
    }
}

function sendRPC_personal_listWallets() {

    return new Promise((resolve, reject) => {

        web3.currentProvider.send({ method: "personal_listWallets", params: [], jsonrpc: "2.0", id: new Date().getTime() },
            function (error, result) { if (error) { reject(error); } else { resolve(result); } });
    }
    );
}
let wallets;
listWallets().then((r) => { console.log("ID:", r.id); wallets = r.result; console.log("Accounts:", wallets); });

3
  • Note that personal API is being deprecated and in practice no user wallet implements this. ethereum.stackexchange.com/questions/82531/… Commented Sep 22, 2020 at 7:26
  • @MikkoOhtamaa can you provide any link to a notice of this - personal API being deprecated? I checked, all I could find is that of it's HTTP provider being deprecated here - web3js.readthedocs.io/en/v1.2.11/… Commented Feb 1, 2022 at 8:19
  • Unfortunately I cannot go to find sources for you after two years. However you can take my word on it: don't try to use it, it was bad idea in 2015 and it is still a bad idea. Commented Feb 1, 2022 at 8:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.