On env HOME override, get-wallet returns same address for different paths

On 0.9.2 of dfx cli, the following is returning the same wallet address, where I expect to get a different wallet address.

#!/bin/bash

basePath=./tmp

mkdir -p "$basePath"/alice
mkdir -p "$basePath"/bob

aliceHome="$basePath"/alice
bobHome="$basePath"/bob

aliceWallet=$(HOME=$aliceHome dfx identity get-wallet)
bobWallet=$(HOME=$bobHome dfx identity get-wallet)

if [[ "$aliceWallet" == "$bobWallet" ]];
then
  echo "👹 Oops! Same wallet address!"

  exit 1
fi

echo "All good! aliceWallet is $aliceWallet and bobWallet is $bobWallet"
1 Like

The expected behaviour is to get a different address, for example, if we change the example above to

aliceWallet=$(HOME=$aliceHome dfx identity get-principal)
bobWallet=$(HOME=$bobHome dfx identity get-principal)

The resulting addresses will be different. Bear in mind that I do not expect to get a “wallet” from this, I’m literally just providing you with an example that overriding HOME allows me to get a different “principal”, as I’d expect for “wallet”. Hope this is clear!

Have you run dfx start ? If not, what’s happening is that dfx identity get-wallet is reporting an error, and the script isn’t noticing that error, instead taking "" as the wallet value.

Two suggestions: add set -e to your script, and run dfx start --background first.

When I did those things, I got this output:

dfx.json not found, using default.
Creating the "default" identity.
  - generating new key at ./tmp/alice/.config/dfx/identity/default/identity.pem
Created the "default" identity.
dfx.json not found, using default.
Creating a wallet canister on the local network.
The wallet canister on the "local" network for user "default" is "rno2w-sqaaa-aaaaa-aaacq-cai"
dfx.json not found, using default.
Creating the "default" identity.
  - generating new key at ./tmp/bob/.config/dfx/identity/default/identity.pem
Created the "default" identity.
dfx.json not found, using default.
Creating a wallet canister on the local network.
The wallet canister on the "local" network for user "default" is "renrk-eyaaa-aaaaa-aaada-cai"
All good! aliceWallet is rno2w-sqaaa-aaaaa-aaacq-cai and bobWallet is renrk-eyaaa-aaaaa-aaada-cai

Thanks for taking your time on this, but unfortunately the wallet addresses are not “”, but actual principal as text. Also, the tests were run while the local replica is available (in any case, I wouldn’t expect this to be required to get-wallet).

I’ll make this clear by putting the addresses in the erroring output:

👹 Oops! Same wallet address, where aliceWallet (qaa6y-5yaaa-aaaaa-aaafa-cai) equals bobWallet (qaa6y-5yaaa-aaaaa-aaafa-cai)!

The modified source script:

#!/bin/bash

basePath=./tmp

mkdir -p "$basePath"/alice
mkdir -p "$basePath"/bob

aliceHome="$basePath"/alice
bobHome="$basePath"/bob

aliceWallet=$(HOME=$aliceHome dfx identity get-wallet)
bobWallet=$(HOME=$bobHome dfx identity get-wallet)

if [[ "$aliceWallet" == "$bobWallet" ]];
then
  echo "👹 Oops! Same wallet address, where aliceWallet ($aliceWallet) equals bobWallet ($bobWallet)!"

  exit 1
fi

echo "All good! aliceWallet is $aliceWallet and bobWallet is $bobWallet"

I’m on macOS Monterey 12.0.1

zsh 5.7.1 (x86_64-apple-darwin18.2.0)

By removing the “tmp” directory and adding a get-principal before the get-wallet. Same issue!

alicePrincipal=$(HOME=$BOB_HOME dfx identity get-principal)
bobPrincipal=$(HOME=$HOME dfx identity get-principal)

Output:

Creating the "default" identity.
  - generating new key at ./tmp/alice/.config/dfx/identity/default/identity.pem
Created the "default" identity.
Creating the "default" identity.
  - generating new key at ./tmp/bob/.config/dfx/identity/default/identity.pem
Created the "default" identity.
👹 Oops! Same wallet address, where aliceWallet (qaa6y-5yaaa-aaaaa-aaafa-cai) equals bobWallet (qaa6y-5yaaa-aaaaa-aaafa-cai)!

Remove .dfx, start local replica --clean

❯ HOME=./tmp/alice dfx identity get-wallet

Creating a wallet canister on the local network.
rrkah-fqaaa-aaaaa-aaaaq-cai
The wallet canister on the "local" network for user "default" is "rrkah-fqaaa-aaaaa-aaaaq-cai"

❯ HOME=./tmp/alice dfx identity list

anonymous
default *

❯ HOME=./tmp/bob dfx identity list

anonymous
default *

Returns same wallet “rrkah-fqaaa-aaaaa-aaaaq-cai”

HOME=./tmp/alice dfx identity get-wallet
HOME=./tmp/bob dfx identity get-wallet

Returns different principals “q7q6t-rrdlh-hncjj-5hvcb-hncb2-4iubz-6fbdp-e2ekv-r5cgw-3j5b3-3qe” and “m2pmo-vkmby-v4v7u-t57g6-i5wi2-l7m55-owtl3-zfqhe-6lw2f-nr2pn-jqe”

HOME=./tmp/alice dfx identity get-principal
HOME=./tmp/bob dfx identity get-principal

Shouldn’t the get-wallet return a different wallet as it works for get-principal? I think so.

The issue is that local wallet addresses are stored in .dfx/local/wallets.json.

Notice in the output above, this occurs twice:

Creating the "default" identity.

This is because .dfx/local/wallets.json stores wallet ids by identity name, for example:

$ cat .dfx/local/wallets.json 
{
  "identities": {
    "default": {
      "local": "rwlgt-iiaaa-aaaaa-aaaaa-cai"
    }
  }
}

You can use identities with different names without separate HOME directories, for example

$ dfx identity new alice
$ dfx --identity alice identity get-wallet
Creating a wallet canister on the local network.
rrkah-fqaaa-aaaaa-aaaaq-cai
The wallet canister on the "local" network for user "alice" is "rrkah-fqaaa-aaaaa-aaaaq-cai"
$ dfx identity new bob
$ dfx --identity bob identity get-wallet
Creating a wallet canister on the local network.
The wallet canister on the "local" network for user "bob" is "ryjl3-tyaaa-aaaaa-aaaba-cai"
ryjl3-tyaaa-aaaaa-aaaba-cai

If you really want different HOME directories, you can do that, but you’ll need to also give them different names. Otherwise, they will all be called “default” and will share the same wallet address (except that only one will actually be the controller)

I personally find that it lacks consistency and I’d improve the dev experience here by providing the behaviour we get with the likes of get-principal, it’s simple and there’s no need for name hinting. For this reason, it looks to me as an unintentional bug or a simple bad dev experience, so I leave my feedback hoping it’s improved in the future. Thanks!

Modified the example script I provided to demonstrate the problem and I’m afraid to say that the suggestion when pairing with the HOME override approach, on naming the identity does not work!

At this point, it seems clear this is a problem and it simply fails to provide the expected result.

#!/bin/bash

basePath=./tmp

mkdir -p "$basePath"/alice
mkdir -p "$basePath"/bob

aliceHome="$basePath"/alice
bobHome="$basePath"/bob

HOME=$aliceHome dfx identity new alice
HOME=$bobHome dfx identity new bob

aliceWallet=$(HOME=$aliceHome dfx identity get-wallet)
bobWallet=$(HOME=$bobHome dfx identity get-wallet)

if [[ "$aliceWallet" == "$bobWallet" ]];
then
  echo "👹 Oops! Same wallet address, where aliceWallet ($aliceWallet) equals bobWallet ($bobWallet)!"

  exit 1
fi

echo "All good! aliceWallet is $aliceWallet and bobWallet is $bobWallet"

Here’s the output:

Creating identity: "alice".
Creating the "default" identity.
  - generating new key at ./tmp/alice/.config/dfx/identity/default/identity.pem
Created the "default" identity.
Created identity: "alice".
Creating identity: "bob".
Creating the "default" identity.
  - generating new key at ./tmp/bob/.config/dfx/identity/default/identity.pem
Created the "default" identity.
Created identity: "bob".
👹 Oops! Same wallet address, where aliceWallet (rwlgt-iiaaa-aaaaa-aaaaa-cai) equals bobWallet (rwlgt-iiaaa-aaaaa-aaaaa-cai)!
  • Has overridden HOME? Yes
  • Has renamed the identity to avoid “default”? Yes
  • Does it work? :expressionless:

Just to be clear, if someone asks themselves, why not dfx identity use <Name>?

When writing scripts for processes like CI, Tests, etc it’s a bad practice to keep switching via dfx identity use X as it’s prone to errors, forgetting which state a user started or ended, etc.

Note: Missed the --identity, instead of dfx identity use, so on the dfx identity use approach seems evident is bad, will use the --identity flag

1 Like

Here’s an update for the example script.

Seems a bit too verbose for something that could compute from overridden HOME. For such a simple example, coupling HOME and --identity is redundant, as we can observe here:

#!/bin/bash

basePath=./tmp

mkdir -p "$basePath"/alice
mkdir -p "$basePath"/bob

aliceHome="$basePath"/alice
bobHome="$basePath"/bob

HOME=$aliceHome dfx identity new alice
HOME=$bobHome dfx identity new bob

aliceWallet=$(HOME=$aliceHome dfx --identity alice identity get-wallet)
bobWallet=$(HOME=$bobHome dfx --identity bob identity get-wallet)

if [[ "$aliceWallet" == "$bobWallet" ]];
then
  echo "👹 Oops! Same wallet address, where aliceWallet ($aliceWallet) equals bobWallet ($bobWallet)!"

  exit 1
fi

echo "All good! aliceWallet is $aliceWallet and bobWallet is $bobWallet"

Output

Creating identity: "alice".
Creating the "default" identity.
  - generating new key at ./tmp/alice/.config/dfx/identity/default/identity.pem
Created the "default" identity.
Created identity: "alice".
Creating identity: "bob".
Creating the "default" identity.
  - generating new key at ./tmp/bob/.config/dfx/identity/default/identity.pem
Created the "default" identity.
Created identity: "bob".
Creating a wallet canister on the local network.
The wallet canister on the "local" network for user "alice" is "rrkah-fqaaa-aaaaa-aaaaq-cai"
Creating a wallet canister on the local network.
The wallet canister on the "local" network for user "bob" is "ryjl3-tyaaa-aaaaa-aaaba-cai"
All good! aliceWallet is rrkah-fqaaa-aaaaa-aaaaq-cai and bobWallet is ryjl3-tyaaa-aaaaa-aaaba-cai
1 Like